2.2 Android NuPlayer流程: MediaPlayer的创建

  • A+
所属分类:音视频

2.2.MediaPlayer的创建

按照播放的流程我们先分析下MediaPlayer的创建

[-->MediaPlayer.java]
public class MediaPlayer extends PlayerBase
{
...
private static native final void native_init();
private native final void native_setup(Object mediaplayer_this);
...
    static {
        System.loadLibrary("media_jni");
        native_init();
    }
    public MediaPlayer() {
    ...
        native_setup(new WeakReference<MediaPlayer>(this));
    }
    ...
}

 

在静态代码中加载so,并且调用native_init 是一个native方法。接下来在构造函数中调用native_setup方法,将自己传递下去。我们来看下jni中所作的事情。

2.2.1 JNI的加载

[-->android_media_mediaplayer.cpp]
static const JNINativeMethod gMethods[] = {
   ...
    {"_prepare",            "()V",                              (void *)android_media_MediaPlayer_prepare},
  ...
    {"native_init",         "()V",                              (void *)android_media_MediaPlayer_native_init},
    {"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer_native_setup},
    ...
};

// This function only registers the native methods
static int register_android_media_MediaPlayer(JNIEnv *env)
{
    return AndroidRuntime::registerNativeMethods(env,
                "android/media/MediaPlayer", gMethods, NELEM(gMethods));
}

jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
{
...

    if (register_android_media_MediaPlayer(env) < 0) {
        ALOGE("ERROR: MediaPlayer native registration failed\n");
        goto bail;
    }
...
}

 

系统调用JNI的时候会调用JNI_OnLoad函数,JNI_OnLoad函数会调用register_android_media_MediaPlayer,这里会调用一系列的和上层对接的方法,这里就省略了。

2.2.2 本地初始化native_init

根据对应关系native_init 所对应的本地方法是android_media_MediaPlayer_native_init

[-->android_media_mediaplayer.cpp]
static void
android_media_MediaPlayer_native_init(JNIEnv *env)
{
    jclass clazz;

    clazz = env->FindClass("android/media/MediaPlayer");
    if (clazz == NULL) {
        return;
    }

    fields.context = env->GetFieldID(clazz, "mNativeContext", "J");
    if (fields.context == NULL) {
        return;
    }

    fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");
    if (fields.post_event == NULL) {
        return;
    }

   ...
    gPlaybackParamsFields.init(env);
    gSyncParamsFields.init(env);
}

 

这些初始化都是一些有用的东西,但是一时间记不了这么多,我们只提一个变量fields.post_event这个变量记录的是上层java中的postEventFromNative的方法,它是用来传回调事件的,比如播放错误的一些事件都是通过它从cpp-->java的。

2.2.3 设置本地的播放器 native_setup

熟悉Android的框架的都知道,Android喜欢通过JNI 把Java和cpp联系起来,并且Java上面的类在下面一定有一个对应的类。native_setup所对应的jni的方法是android_media_MediaPlayer_native_setup

[-->android_media_mediaplayer]
static void
android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
...
    sp<MediaPlayer> mp = new MediaPlayer();
...
    // create new listener and give it to MediaPlayer
    sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this);
    mp->setListener(listener);
...
    setMediaPlayer(env, thiz, mp);
}

 

 

这里分为三步:

1. new 了个本地的MediaPlayer

2. 新建一个JNIMediaPlayerListener 监听类 并设置给刚才new出来的MediaPlayer(和上面讲的fields.post_event是相互对应的)

3. 将新建的mp setMediaPlayer保存起来

我们这里又要分步看了。

2.2.3.1 new 了个本地的MediaPlayer

[-->mediaplayer.cpp]
MediaPlayer::MediaPlayer()
{
...
    mLeftVolume = mRightVolume = 1.0;
    mVideoWidth = mVideoHeight = 0;
    mLockThreadId = 0;
    mAudioSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
    AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
...
}

 

这里其实没做什么事,但是比较重要的是它与AudioSystem的交互,实际上是向AudioFlinger 申请了个id,告诉AudioFlinger我准备需要有音频的输出,你准备下,给我个mAudioSessionId,等下我来找你。

2.2.3.2 新建一个JNIMediaPlayerListener

[-->android_media_mediaplayer.cpp]
JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
{
...
    jclass clazz = env->GetObjectClass(thiz);
...
}


void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
{
...
    env->CallStaticVoidMethod(mClass, fields.post_event, mObject,msg, ext1, ext2, jParcel)
...
}

 

这个类什么都没做,它就是设置给刚才新建的本地的MediaPlayer,本地的MediaPlayer如果有消息会调用JNIMediaPlayerListener的notify,方法而notify方法就像刚才所说的那样会调用到java。

2.2.3.3 setMediaPlayer

[-->android_media_mediaplayer.cpp]
static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz)
{
    Mutex::Autolock l(sLock);
    MediaPlayer* const p = (MediaPlayer*)env->GetLongField(thiz, fields.context);
    return sp<MediaPlayer>(p);
}

static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player)
{
...
    env->SetLongField(thiz, fields.context, (jlong)player.get());
    return old;
...    
}

 

有set就有get,本地的MediaPlayer创建完成后 将其设置的fields.context全局变量中,get可将其拿出来用。

2.0 Android NuPlayer流程简介
2.1 Android NuPlayer流程 —进程启动
2.2 Android NuPlayer流程—-MediaPlayer的创建
2.3 Android NuPlayer流程 -MediaPlayer的setDataSource流程
2.4 Android NuPlayer流程—-Nuplayer的工作原理
2.5 Android NuPlayer流程—-视频和音频的输出

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: