android media mediaplayer,MediaPlayer的创建 | 安卓音视频播放流程(基于Android7.0)|神农笔记...

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(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 mp = new MediaPlayer();

...

// create new listener and give it to MediaPlayer

sp 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 getMediaPlayer(JNIEnv* env, jobject thiz)

{

Mutex::Autolock l(sLock);

MediaPlayer* const p = (MediaPlayer*)env->GetLongField(thiz, fields.context);

return sp(p);

}

static sp setMediaPlayer(JNIEnv* env, jobject thiz, const sp& player)

{

...

env->SetLongField(thiz, fields.context, (jlong)player.get());

return old;

...

}

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值