概述
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 failedn");
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可将其拿出来用。
最后
以上就是斯文棒球为你收集整理的android media mediaplayer,MediaPlayer的创建 | 安卓音视频播放流程(基于Android7.0)|神农笔记...的全部内容,希望文章能够帮你解决android media mediaplayer,MediaPlayer的创建 | 安卓音视频播放流程(基于Android7.0)|神农笔记...所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复