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 ;

     

  • 相关阅读:
    网站中三角小图标的制作方法
    table版网站首页制作
    网站首页之早期布局
    图标字体使用方法总结
    导航制作方法总结之二
    导航制作方法总结之一
    关于网站建设之清除浏览器默认样式
    MySql操作时间
    POI操作excel
    Spring定时器,定时执行(quartz)
  • 原文地址:https://www.cnblogs.com/roger-yu/p/8094432.html
Copyright © 2011-2022 走看看