MediaPlayer源码简单分析

本文详细解析了Android系统的MediaPlayer架构,从Java层到JNI层再到C++层,包括MediaPlayer.java、com_android_MediaPlayer.cpp、mediaplayer.h/.cpp等文件的分析。深入介绍了MediaPlayer的初始化过程、事件回调机制及不同播放器类型的创建流程。

1、MediaPlayer.java
位于/frameworks/base/media/java/android/media目录,主要是对底层media player的封装,主要的方法如seek、pause、play等也都有对应的jni方法。在MediaPlayer类加载时,调用了native_init()方法。该方法主要是jni层的初始化,将jni层的一些变量和java层的一些方法、变量对应起来。在创建MediaPlayer对象时,调用了native_setup()方法。该方法将java层对象和jni层的对象一一对应起来,并绑定jni层的事件回调对象。

2、com_android_MediaPlayer.cpp
位于/frameworks/base/media/jni目录。起到一个承上启下的作用,相当于java层MediaPlayer和native层MediaPlayer之间的桥梁。有几个重要的jni方法和结构体:

// jni层的初始化
android_media_MediaPlayer_native_init(JNIEnv *env)
{
    jclass clazz;

    clazz = env->FindClass("android/media/MediaPlayer"); // 获取java MediaPlayer类对象
    if (clazz == NULL) {
        return;
    }

    // 获取java MediaPlayer的字段指针,用于保存native MediaPlayer的对象指针。通过该指针,
    // 所有的java MediaPlayer对象的native方法,都调用到了native MediaPlayer对象的对应方法
    fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
    if (fields.context == NULL) {
        return;
    }

    // java MediaPlayer的事件回调方法
    fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");
    if (fields.post_event == NULL) {
        return;
    }

    // 和mNativeContext类似,将native SurfaceTexture对象指针保存在java对象的一个字段中
    fields.surface_texture = env->GetFieldID(clazz, "mNativeSurfaceTexture", "I");
    if (fields.surface_texture == NULL) {
        return;
    }
}

// java层native_setup(weak reference)的实现,thiz是java层MediaPlayer,weak_this则是java层MediaPlayer的weak reference。
static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
    ALOGV("native_setup");
    // 创建native media player,即BnMediaPlayer对象。MediaPlayer继承与BnMediaPlayer
    sp<MediaPlayer> mp = new MediaPlayer();
    if (mp == NULL) {
        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
        return;
    }

    // create new listener and give it to MediaPlayer
    // 使用java层MediaPlayer对象和其弱引用,创建一个事件回调listener对象
    sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
    mp->setListener(listener); // 给MediaPlayer设置MediaPlayerListener事件回调

    // Stow our new C++ MediaPlayer in an opaque field in the Java object.
    // 将native MediaPlayer对象指针存入java MediaPlayer的一个字段中
    setMediaPlayer(env, thiz, mp);  
}

// thiz参数是一个java层MediaPlayer对象,而weak_thiz参数则是这个java对象的weak reference
JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
{

    // Hold onto the MediaPlayer class for use in calling the static method
    // that posts events to the application thread.
    jclass clazz = env->GetObjectClass(thiz); // 获取java MediaPlayer的类对象
    if (clazz == NULL) {
        ALOGE("Can't find android/media/MediaPlayer");
        jniThrowException(env, "java/lang/Exception", NULL);
        return;
    }
    mClass = (jclass)env->NewGlobalRef(clazz); // 保存java MediaPlayer的类对象

    // We use a weak reference so the MediaPlayer object can be garbage collected.
    // The reference is only used as a proxy for callbacks.
    mObject  = env->NewGlobalRef(weak_thiz);  // 保存java MediaPlayer的弱引用
}

JNIMediaPlayerListener::~JNIMediaPlayerListener()
{
    // remove global references
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    env->DeleteGlobalRef(mObject);
    env->DeleteGlobalRef(mClass);
}

// native层事件通知到java层
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);
        }
    } 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();
    }
}

static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
{
    Mutex::Autolock l(sLock);

    // 从java MediaPlayer对象的字段中,获取native MediaPlayer的对象指针
    MediaPlayer* const p = (MediaPlayer*)env->GetIntField(thiz, fields.context);
    return sp<MediaPlayer>(p);
}

static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
{
    Mutex::Autolock l(sLock);
    sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context);
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值