Android MediaPlayer架構 -- 前言小知識點(一)

  在Android中能夠使用MediaPlayer+SurfaceView來實現一個簡單的多媒體播放器。java

一  構造函數

  java MediaPlayer class 的源碼位置:frameworks\base\media\java\android\media\MediaPlayer.javaandroid

  首先看一下其構造函數:ide

 1     public MediaPlayer() {  2 
 3  Looper looper;  4         if ((looper = Looper.myLooper()) != null) {  5             mEventHandler = new EventHandler(this, looper);  6         } else if ((looper = Looper.getMainLooper()) != null) {  7             mEventHandler = new EventHandler(this, looper);  8         } else {  9             mEventHandler = null; 10  } 11 
12         mTimeProvider = new TimeProvider(this); 13         mOpenSubtitleSources = new Vector<InputStream>(); 14         IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE); 15         mAppOps = IAppOpsService.Stub.asInterface(b); 16 
17         /* Native setup requires a weak reference to our object. 18  * It's easier to create it here than in C++. 19          */
20         native_setup(new WeakReference<MediaPlayer>(this)); // 在實例化MediaPlayer對象時,會調用一個native_setup方法 21     }

  在實例化MediaPlayer對象時,會調用一個native_setup方法:函數

1 private native final void native_setup(Object mediaplayer_this);

  在JNI代碼(frameworks\base\media\jni\android_media_MediaPlayer.cpp)中能夠找到對應的native函數:oop

 1 static void
 2 android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)  3 {  4     ALOGV("native_setup");  5     sp<MediaPlayer> mp = new MediaPlayer(); // 實例化一個native MediaPlayer(frameworks\av\media\libmedia\mediaplayer.cpp)  6     if (mp == NULL) {  7         jniThrowException(env, "java/lang/RuntimeException", "Out of memory");  8         return;  9  } 10 
11     // create new listener and give it to MediaPlayer
12     sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this); 13     mp->setListener(listener); 14 
15     // Stow our new C++ MediaPlayer in an opaque field in the Java object.
16  setMediaPlayer(env, thiz, mp); 17 }

  在JNI能夠看到,sp<MediaPlayer> mp = new MediaPlayer() 這個native MediaPlayer會去和media service進行交互實現真正的播放功能。post

 

 二  設置Listener

  在JNI 函數 android_media_MediaPlayer_native_setup 中有爲MediaPlayer設置listener,目的就是經過callback的方式將player的事件上傳至java層,以便用戶作出對應的處理ui

1     // create new listener and give it to MediaPlayer
2     sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this); 3     mp->setListener(listener);

 

  從上面這兩行代碼能夠看到,首先咱們實例化一個JNIMediaPlayerListener對象,而後將這個對象傳遞給了C++ MediaPlayer,在frameworks\av\include\media\mediaplayer.h中定義了listener的接口形式:this

1 // ref-counted object for callbacks
2 class MediaPlayerListener: virtual public RefBase 3 { 4 public: 5     virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0; 6 };

  在JNI代碼中,JNIMediaPlayerListener class 正是一個MediaPlayerListener的子類,實現了notify函數,其定義以下:spa

// ref-counted object for callbacks
class JNIMediaPlayerListener: public MediaPlayerListener { public: JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz); ~JNIMediaPlayerListener(); virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL); private: JNIMediaPlayerListener(); jclass mClass; // Reference to MediaPlayer class
    jobject     mObject;    // Weak ref to MediaPlayer Java object to call on
};

 

   callback事件的傳遞主要是經過notify函數來完成的,下面看一下這個函數的具體實現過程:code

void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj) { JNIEnv *env = AndroidRuntime::getJNIEnv(); if (obj && obj->dataSize() > 0) { jobject jParcel = createJavaParcelObject(env); if (jParcel != NULL) { Parcel* nativeParcel = parcelForJavaObject(env, jParcel); nativeParcel->setData(obj->data(), obj->dataSize()); env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, jParcel); env->DeleteLocalRef(jParcel); } } else { env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, NULL); } if (env->ExceptionCheck()) { ALOGW("An exception occurred while notifying an event."); LOGW_EX(env); env->ExceptionClear(); } }
  • msg, ext1, ext2, obj 攜帶着事件相關信息及數據;

  • 經過env->CallStaticVoidMethod()方法去回調MediaPlayer(java)的 fields.post_event 方法,並將事件信息及數據傳遞過去;

  • fields.post_event對應於MediaPlayer的java 方法 postEventFromNative;

  • fields.post_event是在MediaPlayer第一次加載時在android_media_MediaPlayer_native_init中初始化的;

三  小結

  這一篇介紹的內容很簡單,主要是對java層的MediaPlayer, JNI層,及native層的MediaPlayer如何關聯起來的有個基本的認識與瞭解。

  簡單兩點概述:

  1. java層的MediaPlayer提供了java API供用戶調用實現playback功能,但其功能的實現還會串接到JNI層,在JNI層會去實例化一個native MediaPlayer,這個native MediaPlayer會和MediaPlayerService進行交互實現真正的播放功能;
  2. 設置listener的目的就是經過回調的方式未來自native的事件進行上傳,以便用戶在java層作出處理,就這篇而言能夠暫時這樣理解流程: MediaPlayerService-->native MediaPlayer-->JNI->java MediaPlayer ;
相關文章
相關標籤/搜索