Android MediaPlayer 源码分析(一) —— MediaPlayer的创建过程和交互流程

617 阅读5分钟

MediaPlayer概述

MediaPlayer是Android多媒体框架中的主要组件,通过MediaPlayer可以实现音视频的获取、解码、播放等功能。

MediaPlayer的简单使用:

    //prepareAsync的回调接口,执行start方法
    MediaPlayer.OnPreparedListener mOnPreparedListener = mediaPlayer -> mediaPlayer.start();
    
    mMediaPlayer = new MediaPlayer();
    //设置视频源
    mMediaPlayer.setDataSource(mPath);
    //设置播放显示控件
    mMediaPlayer.setDisplay(mSurfaceHolder);
    //设置prepareAsync回调
    mMediaPlayer.setOnPreparedListener(mOnPreparedListener);
    //异步prepare
    mMediaPlayer.prepareAsync();

MediaPlayer执行过程中,各种状态变化的流程,这里就不做详细分析,请自行查看官方文档

image

MediaPlayer的创建过程

首先看MediaPlayer的静态代码块,在类初始化的时候加载.so库,并调用初始化函数 native_init() 。

// frameworks/base/media/java/android/media/MediaPlayer.java

    static {
        //so库路径在system/lib64/libmedia_jni.so 和 system/lib/libmedia_jni.so
        System.loadLibrary("media_jni");
        //native方法
        native_init();
    }

native_init()方法调用到了 android_media_MediaPlayer.cpp 中的 android_media_MediaPlayer_native_init()方法,这里使用的是JNI的动态注册的方式,将JNI方法与实际方法对齐。

// frameworks/base/media/jni/android_media_MediaPlayer.cpp

static const JNINativeMethod gMethods[] = {

    ...
    
    {"native_init",         "()V",                              (void *)android_media_MediaPlayer_native_init},
    {"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer_native_setup},
    
    ...
    
};

在android_media_MediaPlayer_native_init()方法中,主要是获取java层中的一系列变量,并与C++层的变量关联起来。

// frameworks/base/media/jni/android_media_MediaPlayer.cpp

static void
android_media_MediaPlayer_native_init(JNIEnv *env)
{
    jclass clazz;
    //获取MediaPlayer class对象
    clazz = env->FindClass("android/media/MediaPlayer");
    if (clazz == NULL) {
        return;
    }
    //获取MediaPlayer的mNativeContext对象,这是native层MediaPlayer的指针值,java层声明为 private long mNativeContextl;
    fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
    if (fields.context == NULL) {
        return;
    }

    //获取MediaPlayer的postEventFromNative方法,是native层传递给java层的消息机制,
    //java层声明为 private static void postEventFromNative(Object mediaplayer_ref, int what, int arg1, int arg2, Object obj)
    fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");
    if (fields.post_event == NULL) {
        return;
    }
    
    //获取mNativeSurfaceTexture对象,用于缓存native层的surface信息,java层声明为 private long mNativeSurfaceTexture;
    fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "J");
    if (fields.surface_texture == NULL) {
        return;
    }
    
    //释放 MediaPlayer class对象
    env->DeleteLocalRef(clazz);
    
    ...
    
}

再看MediaPlayer的构造方法, 创建EventHandler接收处理native层回调事件,调用native层的native_setup方法,同上使用动态注册jni方法。

// frameworks/base/media/java/android/media/MediaPlayer.java

    public MediaPlayer() {
    
        ...
        // Handler机制,主要是用于接收native层回调事件后的处理。    
        Looper looper;
        if ((looper = Looper.myLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else if ((looper = Looper.getMainLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else {
            mEventHandler = null;
        }
        
        ...
        
        // 调用native_setup方法
        native_setup(new WeakReference<MediaPlayer>(this));

        ...
    }

调用的android_media_MediaPlayer_native_setup()方法,创建C++层的MediaPlayer对象,并设置监听回调接口;将MediaPlayer对象的指针赋值到Java层的MediaPlayer.java的mNativeContext属性,为long类型。

// frameworks/base/media/jni/android_media_MediaPlayer.cpp

static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
    ALOGV("native_setup");
    // 创建C++层的MediaPlayer对象mp
    sp<MediaPlayer> mp = new MediaPlayer();
    if (mp == NULL) {
        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
        return;
    }

    // 给MediaPlayer设置监听回调接口
    // create new listener and give it to MediaPlayer
    sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
    mp->setListener(listener);

    // 将mp的指针赋值到Java层的MediaPlayer.java的mNativeContext 
    // Stow our new C++ MediaPlayer in an opaque field in the Java object.
    setMediaPlayer(env, thiz, mp);
}

C++层的MediaPlayer类,除了实现MediaPlayer在Native的代码逻辑,还继承了BnMediaPlayerClient类和IMediaDeathNotifier接口类。

// frameworks/av/media/libmedia/include/media/mediaplayer.h

class MediaPlayer : public BnMediaPlayerClient,
                    public virtual IMediaDeathNotifier
{
    ...
}

BnMediaPlayerClient继承BnInterface,从这里可以看出,BnMediaPlayerClient主要是与MediaPlayerService通信,通过notify接口方法来回调对MediaPlayer的状态逻辑。

// frameworks/av/media/libmedia/include/media/IMediaPlayerClient.h

class IMediaPlayerClient: public IInterface
{
public:
    DECLARE_META_INTERFACE(MediaPlayerClient);

    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;
};

class BnMediaPlayerClient: public BnInterface<IMediaPlayerClient>
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
};

至此,MediaPlayer的创建过程分析完毕,主要步骤如下:

  1. 在MediaPlayer类初始化时,加载so库文件,动态注册Jni函数。
  2. 调用native_init方法,将Java层和Jni层的属性和方法关联起来。
  3. MediaPlayer构造时,调用native_setup方法,创建Native层的MediaPlayer对象,并建立交互方式。

MediaPlayer与native层的交互流程

当MediaPlayerService传递消息给BnMediaPlayerClient后,Native层是如何将消息回调给Java层MediaPlayer的呢?

从IMediaPlayerClient.h的代码可以看到,binder机制会调用到BnMediaPlayerClient的onTransact方法,从而调用到IMediaPlayerClient的notify方法,mediaplayer.cpp则实现了这个notify方法。

// frameworks/av/media/libmedia/mediaplayer.cpp

void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
{
    ...
    
    //根据传递过来的msg类型,执行逻辑...
    switch (msg) {
    
    ...
    
    }
    
    ...
    
    // 通过listener->notify将消息回调上去
    // this prevents re-entrant calls into client code
    if ((listener != 0) && send) {
        Mutex::Autolock _l(mNotifyLock);
        ALOGV("callback application");
        listener->notify(msg, ext1, ext2, obj);
        ALOGV("back from callback");
    }
}

这里的listener,就是在android_media_MediaPlayer_native_setup方法中,mp->setListener(listener)设置进去的,它是JNIMediaPlayerListener类型。

// frameworks/base/media/jni/android_media_MediaPlayer.cpp

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());
            //调用fields.post_event方法
            env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
                    msg, ext1, ext2, jParcel);
            env->DeleteLocalRef(jParcel);
        }
    } else {
        //调用fields.post_event方法
        env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
                msg, ext1, ext2, NULL);
    }
    
    ...
    
}

通过JNIEnv调用的静态方法fields.post_event,就是在android_media_MediaPlayer_native_init方法中关联的MediaPlayer的postEventFromNative方法。

// frameworks/base/media/java/android/media/MediaPlayer.java

private static void postEventFromNative(Object mediaplayer_ref,
                                            int what, int arg1, int arg2, Object obj)
{
    //这个mp就是APP中创建的MediaPlayer的实例对象
    final MediaPlayer mp = (MediaPlayer)((WeakReference)mediaplayer_ref).get();
        
    //根据what执行代码逻辑...
    switch (what) {
    
    ...
    
    }
    
    //将回调数据封装成Message发送
    if (mp.mEventHandler != null) {
        Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
        mp.mEventHandler.sendMessage(m);
    }
}

这个mp就是APP中创建的MediaPlayer的实例对象,由于postEventFromNative是静态方法,所以需要通过Jni层中的软应用对象来获取MediaPlayer的实例对象,最后发送到该实例中的mEventHandler来处理。

// frameworks/base/media/java/android/media/MediaPlayer.java

private class EventHandler extends Handler
{
    private MediaPlayer mMediaPlayer;

    public EventHandler(MediaPlayer mp, Looper looper) {
        super(looper);
        mMediaPlayer = mp;
    }

    @Override
    public void handleMessage(Message msg) {
            
        ...
            
        switch(msg.what) {
        case MEDIA_PREPARED:
                
            ...
            
            //回调onPrepared到APP中
            OnPreparedListener onPreparedListener = mOnPreparedListener;
            if (onPreparedListener != null)
                onPreparedListener.onPrepared(mMediaPlayer);
            return;
            
            ...
        }
        
        ...
    }
    
    ...
}

EventHandler就是一个Handler对象,它在MediaPlayer构造函数中就创建好了,它在handleMessage中执行各种从底层传递上来的消息,并通过APP注册的回调接口回调到APP中。

小结

本文分析了MediaPlayer的创建过程和消息回调流程,其中最主要的部分应当是Java层和Native层的关联和交互,两者如何相互调用,如何持有双方的引用和指针,如何管理生命周期,如何传递消息等,这些设计和逻辑都值得我们参考和学习。

最后通过一张图来梳理本文内容的全过程。

image

注:本文分析的Android源码版本为 Android 11

参考资料

官方文档

MediaPlayer与native层的交互流程