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执行过程中,各种状态变化的流程,这里就不做详细分析,请自行查看官方文档。

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的创建过程分析完毕,主要步骤如下:
- 在MediaPlayer类初始化时,加载so库文件,动态注册Jni函数。
- 调用native_init方法,将Java层和Jni层的属性和方法关联起来。
- 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层的关联和交互,两者如何相互调用,如何持有双方的引用和指针,如何管理生命周期,如何传递消息等,这些设计和逻辑都值得我们参考和学习。
最后通过一张图来梳理本文内容的全过程。
注:本文分析的Android源码版本为 Android 11