zoukankan      html  css  js  c++  java
  • Android MediaPlayer架构 -- 前言小知识点(一)

      在Android中可以使用MediaPlayer+SurfaceView来实现一个简单的多媒体播放器。

    一  构造函数

      java MediaPlayer class 的源码位置:frameworksasemediajavaandroidmediaMediaPlayer.java

      首先看一下其构造函数:

     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代码(frameworksasemediajniandroid_media_MediaPlayer.cpp)中可以找到对应的native函数:

     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(frameworksavmedialibmediamediaplayer.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进行交互实现真正的播放功能。

     

     二  设置Listener

      在JNI 函数 android_media_MediaPlayer_native_setup 中有为MediaPlayer设置listener,目的就是通过callback的方式将player的事件上传至java层,以便用户做出对应的处理

    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,在frameworksavincludemediamediaplayer.h中定义了listener的接口形式:

    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函数,其定义如下:

    // 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函数来完成的,下面看一下这个函数的具体实现过程:

    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 ;

     

  • 相关阅读:
    398. Random Pick Index
    382. Linked List Random Node
    645. Set Mismatch
    174. Dungeon Game
    264. Ugly Number II
    115. Distinct Subsequences
    372. Super Pow
    LeetCode 242 有效的字母异位词
    LeetCode 78 子集
    LeetCode 404 左叶子之和
  • 原文地址:https://www.cnblogs.com/roger-yu/p/8094432.html
Copyright © 2011-2022 走看看