- 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流程—-视频和音频的输出
您可以选择一种方式赞助本站
支付宝扫一扫赞助
微信钱包扫描赞助
赏