In Android, MediaPlayer is used to play audio and video files, and here is an analysis of how MediaPlayer is called in the framework layer, MediaPlayer code is located at:./frameworks/base/media/ Java/android/media/mediaplayer.java the code used below is based on Android 4.4
When opened, there is a static code block that loads the library file, as long as the class is created and the library is loaded.
static { system.loadlibrary ("Media_jni"); Native_init (); }
The source code for libmedia_jni.so is located at:./frameworks/base/media/jni
There is a makefile file in the Jni folder android.mk
Local_path:= $ (call My-dir) include $ (clear_vars) local_src_files:= android_media_imagereader.cpp Android_media_medi ACrypto.cpp android_media_mediacodec.cpp android_media_mediacodeclist.cpp android_media_mediadrm.cpp Andro Id_media_mediaextractor.cpp android_media_mediamuxer.cpp android_media_mediaplayer.cpp Android_media_MediaReco Rder.cpp android_media_mediascanner.cpp android_media_mediametadataretriever.cpp android_media_resampleinputst Ream.cpp android_media_mediaprofiles.cpp android_media_amrinputstream.cpp android_media_utils.cpp android_ Mtp_mtpdatabase.cpp android_mtp_mtpdevice.cpp android_mtp_mtpserver.cpp local_shared_libraries: = Libandroid_r Untime libnativehelper libutils libbinder libmedia libskia libui liblog libcutils LIBG UI Libstagefright libstagefright_foundation libcamera_client libmtp libusbhost libexif Libstag Efright_amrnb_common LOCAl_required_modules: = libjhead_jnilocal_static_libraries: = libstagefright_amrnbenclocal_c_includes + + extern Al/libexif/external/tremor/tremor Frameworks/base/core/jni Frameworks/av/media/libmedia frameworks/av/med Ia/libstagefright frameworks/av/media/libstagefright/codecs/amrnb/enc/src frameworks/av/media/libstagefright/ Codecs/amrnb/common Frameworks/av/media/libstagefright/codecs/amrnb/common/include $ (TOP)/MEDIATEK/EXTERNAL/AMR FRAMEWORKS/AV/MEDIA/MTP Frameworks/native/include/media/openmax $ (call include-path-for, Libhardware)/hardware System/media/camera/include $ (pv_includes) $ (jni_h_include) $ (call include-path-for, CORECG graphics) ifeq ( $ (Strip $ (mtk_tb_debug_support)), yes) Local_c_includes + = $ (mtk_path_source)/frameworks/base/include endififeq ($ ( Strip $ (mtk_high_quality_thumbnail)), yes) Local_cflags + =-dmtk_high_quality_thumbnailendififeq ($ (Strip $ (MTK_USE_ Android_mm_default_code), yes) local_cflags + =-dandroid_default_codeendiflocal_cflags +=local_ldlibs: =-lpthreadlocal_module:= libmedia_jniinclude $ (BUILD_ shared_library) # Build libsoundpool.so# build Libaudioeffect_jni.soinclude $ (call all-makefiles-under,$ (LOCAL_PATH))
local_module:= Libmedia_jni generates LIBMEDIA_JNI library after compiling
There are four overloaded functions to open a file
Setdatasource (String Path)
Setdatasource (FileDescriptor FD)
Setdatasource (context context, URI Uri)
Setdatasource (filedescriptor fd, long offset, long length)
In the app, such as native music
/** * M:add Async prepare to Aviod ANR, add information and duration Update listener * * @param Player the MediaPlayer * @param path The data source path * @param async m:use Async Prepare if it ' s set True. * @return If Set Data source success, return True, otherwise false. */Private Boolean Setdatasourceimpl (MediaPlayer player, String path, Boolean async) {MUSICLOGUTILS.D (T AG, "Setdatasourceimpl (" + path + "); async =" + Async "; try {player.reset (); if (async) {Player.setonpreparedlistener (Preparedlistener); } else {player.setonpreparedlistener (null); } if (Path.startswith ("content://")) {Player.setdatasource (Mediaplaybackservice.this, U Ri.parse (path)); } else {///M:add Add for DRM secure flag @{mediaplayerex.setcontextforsecureflag (player,medIaPlaybackService.this.getApplicationContext ());//@}player.setdatasource (path); }//M:attach auxiliary audio effect only with valid effect ID if (Mauxeffectid > 0) { Player.attachauxeffect (Mauxeffectid); Player.setauxeffectsendlevel (1.0f); Mwhetherattachwhenpause = false; MUSICLOGUTILS.D (TAG, "setdatasourceimpl:attachauxeffect Mauxeffectid =" + Mauxeffectid); } player.setaudiostreamtype (Audiomanager.stream_music); if (async) {Player.prepareasync (); } else {player.prepare (); }} catch (IOException ex) {//todo:notify The user why the file couldn ' t is opened MUSICLOGUTILS.E (TAG, "Setdatasourceimpl:" + ex); return false; } catch (IllegalArgumentException ex) {//todo:notify The user why the file couldn ' t is opened MUSICLOGUTILS.E (TAG, "Setdatasourceimpl:" + ex); return false; } catch (IllegalStateException ex) {MUSICLOGUTILS.E (TAG, "Setdatasourceimpl:" + ex); return false; } player.setoncompletionlistener (listener); Player.setonerrorlistener (Errorlistener); Player.setoninfolistener (Infolistener); Player.setondurationupdatelistener (Durationlistener); Sendsessionidtoaudioeffect (FALSE); return true; }
Regardless of which function is called in the app, the last in Mediaplayer.java is called
/** * Sets the data source (FileDescriptor) to use. The FileDescriptor must be * seekable (n.b. A localsocket are not seekable). It is the caller's responsibility * to close the file descriptor. The It is safe-to-do as soon-a-call returns. * * @param fd The FileDescriptor for the file, want to play * @param offset the offset into the file where the Data to being played starts, in bytes * @param length The length in bytes of the data to be played * @throws illegals Tateexception if it is called in a invalid state */public void Setdatasource (FileDescriptor fd, long offset, long Length) throws IOException, IllegalArgumentException, illegalstateexception {disableproxylistener (); _setdatasource (fd, offset, length); Private native void _setdatasource (FileDescriptor fd, long offset, long length) throws IOException, Illega Largumentexception, illegalstateexception;
_setdatasource has native modification, is libmedia_jni.so in the method, found./frameworks/base/media/jni/android_media_mediaplayer.cpp
----------------------------------------------------------------------------static Jninativemethod gmethods[] = {{"_setdatasource", "(ljava/lang/string;[ ljava/lang/string; [ljava/lang/string;) V ", (void *) Android_media_mediaplayer_setdatasourceandheaders}, {" _setdatasource ", "(Ljava/io/filedescriptor; JJ) v ", (void *) ANDROID_MEDIA_MEDIAPLAYER_SETDATASOURCEFD}, {" _setvideosurface "," (landroid/view/surface;) v ", (void *) Android_media_mediaplayer_setvideosurface}, {"Prepare", "() V", (voi d *) Android_media_mediaplayer_prepare}, {"Prepareasync", "() V", (void *) android_med Ia_mediaplayer_prepareasync}, {"_start", "() V", (void *) ANDROID_MEDIA_MEDIAPL Ayer_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_m Ediaplayer_pause}, {"IsPlaying", "() Z", (void *) Android_media_mediaplayer_isplay ing}, {"GetCurrentPosition", "() I", (void *) Android_media_mediaplayer_getcurrentposition} , {"Getduration", "() I", (void *) Android_media_mediaplayer_getduration}, {"_rel Ease "," () 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}, {"Islooping", "() Z", (void *) Android_me Dia_mediaplayer_islooping}, {"SetVolume", "(FF) V", (void *) Android_media_mediaplay Er_setvolume}, {"Native_invoke", "(Landroid/os/parcel; Landroid/os/parcel;) I ", (void *) Android_media_mediaplayer_invoke}, {" Native_setmetadatafilter "," (landroid/os/ Parcel;) I ", (void *) Android_media_mediaplayer_setmetadatafilter}, {" Native_getmetadata "," (Zzlandroid/os/parcel;) Z ", (void *) Android_media_mediaplayer_getmetadata}, {" Native_init "," () V ", (void *) Android_media_mediaplayer_native_init}, {"Native_setup", "(Ljava/lang/object;) V", (void *) an Droid_media_mediaplayer_native_setup}, {"Native_finalize", "() V", (void *) Android_media_mediaplayer_native_finalize}, {"Getaudiosessionid", "() I", (void *) android_media_mediaplayer_get_audio_session_id}, {"Setaudiosessionid", "(I) V", (void *) android_media_mediaplayer_set_audio_session_id}, {"Setauxeffectsendlevel", "(F) v", (v OID *) Android_media_mediaplayer_setauxeffectsendlevel}, {"Attachauxeffect", "(I) V", (VO ID *) Android_media_mediaplayer_attachauxeffect}, {"Native_pullbatterydata", "(Landroid/os/parcel;) I", (void *) an Droid_media_mediaplayer_pullbatterydata}, {"Setparameter", "(Ilandroid/os/parcel;) Z", (void *) android_m Edia_mediaplayer_setparameter}, {"GetParameter", "(Ilandroid/os/parcel;) V", (void *) Android_media_media Player_getparameter}, {"Native_setretransmitendpoint", "(ljava/lang/string;i) I", (void *) Android_media_mediaplayer _setretransmitendpoint},{"Setnextmediaplayer", "(Landroid/media/mediaplayer;) V", (void *) Android_media_mediaplayer_setnextmediaplayer}, {" Updateproxyconfig "," (landroid/net/proxyproperties;) V ", (void *) Android_media_mediaplayer_updateproxyconfig},};
Will enter the following function
Static VOIDANDROID_MEDIA_MEDIAPLAYER_SETDATASOURCEFD (jnienv *env, Jobject thiz, jobject filedescriptor, Jlong offset, Jlong length) { sp<mediaplayer> MP = Getmediaplayer (env, thiz); if (MP = = null) { jnithrowexception (env, "java/lang/illegalstateexception", null); return; } if (FileDescriptor = = null) { jnithrowexception (env, "java/lang/illegalargumentexception", null); return; } int FD = Jnigetfdfromfiledescriptor (env, filedescriptor); ALOGV ("Setdatasourcefd:fd%d", FD); Process_media_player_call (env, Thiz, Mp->setdatasource (FD, offset, length), "Java/io/ioexception", " SETDATASOURCEFD failed. ");
Mp->setdatasource (fd, offset, length)//Call Open File method
Open the./frameworks/av/media/libmedia/mediaplayer.cpp Setdatasource has three overloaded functions, depending on the parameters
status_t mediaplayer::setdatasource (int fd, int64_t offset, int64_t length) { ALOGV ("Setdatasource (%d,%lld,%LLD)" , FD, offset, length); status_t err = unknown_error; Const sp<imediaplayerservice>& Service (Getmediaplayerservice ()); if (service! = 0) { sp<imediaplayer> player (service->create (this, Maudiosessionid)); if ((No_error! = dosetretransmitendpoint (player)) | | (No_error! = Player->setdatasource (fd, offset, length))) { player.clear (); } Err = Attachnewplayer (player); } return err;}
Open./frameworks/av/media/libmedia/imediaplayer.cpp Setdatasource also has three overloaded functions, depending on the parameters
status_t setdatasource (int fd, int64_t offset, int64_t length) { Parcel data, reply; Data.writeinterfacetoken (Imediaplayer::getinterfacedescriptor ()); Data.writefiledescriptor (FD); Data.writeint64 (offset); Data.writeint64 (length); Remote ()->transact (SET_DATA_SOURCE_FD, DATA, &reply); return Reply.readint32 (); }
This open file process is for local media files only.
Process_media_player_call (env, Thiz, Mp->setdatasource (FD, offset, length), "Java/io/ioexception", " SETDATASOURCEFD failed. ") Processing based on the returned results
If exception is NULL and Opstatus are not OK, this method sends a error//event to the client application; Otherwise, if exception is not NULL and//opstatus are not OK, this method throws the given exception to the client//appli cation.static void Process_media_player_call (jnienv *env, Jobject thiz, status_t opstatus, const char* exception, Const CH Ar *message) {if (exception = = NULL) {//Don ' t throw exception. Instead, send an event. if (opstatus! = (status_t) OK) {sp<mediaplayer> MP = Getmediaplayer (env, thiz); if (MP! = 0) mp->notify (media_error, opstatus, 0); }} else {//Throw exception! if (Opstatus = = (status_t) invalid_operation) {jnithrowexception (env, "java/lang/illegalstateexception", NUL L); } else if (Opstatus = = (status_t) permission_denied) {jnithrowexception (env, "java/lang/securityexception", NULL); } else if (opstatus! = (status_t) OK) {if (strlen (message) (>) {//If the message is too long, and don ' t bother displaying the status code JNI ThrowException (env, exception, message); } else {char msg[256]; Append the status code to the message sprintf (MSG, "%s:status=0x%x", message, opstatus); Jnithrowexception (env, exception, MSG); } } }}
Other features (start ' Stop ' play ' seek_to) are the same process, the difficulty is the JNI technology and the Aidl in the app, of course, the above is just a simple call process, to more in-depth understanding or take some time.
MediaPlayer of the framework of Android source analysis