目录
简要
流程图
代码分析
1)so库加载及初始化
2)创建Looper线程
3)so相关操作setup
本文主要介绍ijkplayer的初始过程
先看LOG
D/IJKMEDIA: IjkMediaPlayer_native_init
D/IJKMEDIA: IjkMediaPlayer_native_setup
I/IJKMEDIA: av_version_info: ff3.4--ijk0.8.7--20180103--001
D/IJKMEDIA: ffpipeline_create_from_android()
D/IJKMEDIA: ijkmp_set_inject_opaque(0x2736)
D/IJKMEDIA: ijkmp_set_inject_opaque()=void
D/IJKMEDIA: ijkmp_set_ijkio_inject_opaque(0x2736)
D/IJKMEDIA: ijkmp_set_ijkio_inject_opaque()=void
D/IJKMEDIA: ijkmp_android_set_mediacodec_select_callback()
D/IJKMEDIA: IjkMediaPlayer_setVideoSurface
D/IJKMEDIA: ijkmp_set_android_surface(surface=0xbb890bf0)
D/IJKMEDIA: ffpipeline_set_surface()
D/IJKMEDIA: ijkmp_set_android_surface(surface=0xbb890bf0)=void
从Log可以看到,初始化过程主要做了
So库的初始化
创建视频解码器
设置缓冲区队列
解码器选择回调
设置Surface
下面通过代码进行分析
IjkMediaPlayer.java
声明IjkMediaPlayer对象,会调用initPlayer,
ijkMediaPlayer = new IjkMediaPlayer();
public IjkMediaPlayer(IjkLibLoader libLoader) {
initPlayer(libLoader);
}
其中IjkLibLoader为一个lib库封装的加载接口
private void initPlayer(IjkLibLoader libLoader) {
loadLibrariesOnce(libLoader);
initNativeOnce();
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}
/*
* Native setup requires a weak reference to our object. It's easier to
* create it here than in C++.
*/
native_setup(new WeakReference(this));
}
initPlayer主要分三大部分:so库加载及初始化,创建Looper线程,so库setup,下面分步介绍
loadLibrariesOnce会加载播放器所有需要的so库
public static void loadLibrariesOnce(IjkLibLoader libLoader) {
synchronized (IjkMediaPlayer.class) {
if (!mIsLibLoaded) {
if (libLoader == null)
libLoader = sLocalLibLoader;
libLoader.loadLibrary("ijkffmpeg");
libLoader.loadLibrary("ijkplayer");
mIsLibLoaded = true;
}
}
}
initNativeOnce初始化so相关,实则啥也没干
private static void initNativeOnce() {
synchronized (IjkMediaPlayer.class) {
if (!mIsNativeInitialized) {
native_init();
mIsNativeInitialized = true;
}
}
}
通过Jni调用ijkplayer_jni.c
{ "native_init", "(Ljava/lang/Object;)V", (void *) IjkMediaPlayer_native_init},
IjkMediaPlayer_native_init其实啥也没干,就打印了Log
IjkMediaPlayer_native_init(JNIEnv *env)
{
MPTRACE("%s\n", __func__);
}
回来,看看JNI_OnLoad都干了什么:
这些都是给java提供相关的操作接口,都是在这里定义
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv* env = NULL;
g_jvm = vm;
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
return -1;
}
assert(env != NULL);
pthread_mutex_init(&g_clazz.mutex, NULL );
// FindClass returns LocalReference
IJK_FIND_JAVA_CLASS(env, g_clazz.clazz, JNI_CLASS_IJKPLAYER);
(*env)->RegisterNatives(env, g_clazz.clazz, g_methods, NELEM(g_methods) );
ijkmp_global_init();
ijkmp_global_set_inject_callback(inject_callback);
FFmpegApi_global_init(env);
SDL_JNI_OnLoad(vm,reserved);
return JNI_VERSION_1_4;
}
JNI_OnLoad主要做了FFMepg的相关初始化ijkmp_global_init,API初始化FFmpegApi_global_init,及android系统SDL显示相关的初始化SDL_JNI_OnLoad
void ffp_global_init()
{
if (g_ffmpeg_global_inited)
return;
ALOGD("ijkmediaplayer version : %s", ijkmp_version());
/* register all codecs, demux and protocols */
avcodec_register_all();
#if CONFIG_AVDEVICE
avdevice_register_all();
#endif
#if CONFIG_AVFILTER
avfilter_register_all();
#endif
av_register_all();
ijkav_register_all();
avformat_network_init();
av_lockmgr_register(lockmgr);
av_log_set_callback(ffp_log_callback_brief);
av_init_packet(&flush_pkt);
flush_pkt.data = (uint8_t *)&flush_pkt;
g_ffmpeg_global_inited = true;
}
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}
创建Looper线程,这部分不做太多解释
native_setup(new WeakReference(this));
new WeakReference(this) 弱引用变量this传入的上下文
通过Jni调用ijkplayer_jni.c
{ "native_setup", "(Ljava/lang/Object;)V", (void *) IjkMediaPlayer_native_setup },
进入IjkMediaPlayer_native_setup,主要实现了android的surface和解码器的创建,及设置播放器相关上下文和解码器选择回调
IjkMediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
{
MPTRACE("%s\n", __func__);
IjkMediaPlayer *mp = ijkmp_android_create(message_loop);
JNI_CHECK_GOTO(mp, env, "java/lang/OutOfMemoryError", "mpjni: native_setup: ijkmp_create() failed", LABEL_RETURN);
jni_set_media_player(env, thiz, mp);
ijkmp_set_weak_thiz(mp, (*env)->NewGlobalRef(env, weak_this));
ijkmp_set_inject_opaque(mp, ijkmp_get_weak_thiz(mp));
ijkmp_set_ijkio_inject_opaque(mp, ijkmp_get_weak_thiz(mp));
ijkmp_android_set_mediacodec_select_callback(mp, mediacodec_select_callback, ijkmp_get_weak_thiz(mp));
LABEL_RETURN:
ijkmp_dec_ref_p(&mp);
}
其中ijkmp_android_create是ijkplayer_android.c在文件里,是初始化部分的核心,主要工作创建Surface和解码器
IjkMediaPlayer *ijkmp_android_create(int(*msg_loop)(void*))
{
IjkMediaPlayer *mp = ijkmp_create(msg_loop);
if (!mp)
goto fail;
mp->ffplayer->vout = SDL_VoutAndroid_CreateForAndroidSurface();
if (!mp->ffplayer->vout)
goto fail;
mp->ffplayer->pipeline = ffpipeline_create_from_android(mp->ffplayer);
if (!mp->ffplayer->pipeline)
goto fail;
ffpipeline_set_vout(mp->ffplayer->pipeline, mp->ffplayer->vout);
return mp;
fail:
ijkmp_dec_ref_p(&mp);
return NULL;
}
SDL_VoutAndroid_CreateForAndroidSurface()创建Surface,作为视频输出,播放器显示就是通过Surface来显示的
SDL_Vout *SDL_VoutAndroid_CreateForANativeWindow()
{
SDL_Vout *vout = SDL_Vout_CreateInternal(sizeof(SDL_Vout_Opaque));
if (!vout)
return NULL;
SDL_Vout_Opaque *opaque = vout->opaque;
opaque->native_window = NULL;
if (ISDL_Array__init(&opaque->overlay_manager, 32))
goto fail;
if (ISDL_Array__init(&opaque->overlay_pool, 32))
goto fail;
opaque->egl = IJK_EGL_create();
if (!opaque->egl)
goto fail;
vout->opaque_class = &g_nativewindow_class;
vout->create_overlay = func_create_overlay;
vout->free_l = func_free_l;
vout->display_overlay = func_display_overlay;
return vout;
fail:
func_free_l(vout);
return NULL;
}
声明了显示相关的接口
而ffpipeline_create_from_android作用是创建视频解码器的相关操作接口
IJKFF_Pipeline *ffpipeline_create_from_android(FFPlayer *ffp)
{
ALOGD("ffpipeline_create_from_android()\n");
IJKFF_Pipeline *pipeline = ffpipeline_alloc(&g_pipeline_class, sizeof(IJKFF_Pipeline_Opaque));
if (!pipeline)
return pipeline;
IJKFF_Pipeline_Opaque *opaque = pipeline->opaque;
opaque->ffp = ffp;
opaque->surface_mutex = SDL_CreateMutex();
opaque->left_volume = 1.0f;
opaque->right_volume = 1.0f;
if (!opaque->surface_mutex) {
ALOGE("ffpipeline-android:create SDL_CreateMutex failed\n");
goto fail;
}
pipeline->func_destroy = func_destroy;
pipeline->func_open_video_decoder = func_open_video_decoder;
pipeline->func_open_audio_output = func_open_audio_output;
pipeline->func_init_video_decoder = func_init_video_decoder;
pipeline->func_config_video_decoder = func_config_video_decoder;
return pipeline;
fail:
ffpipeline_free_p(&pipeline);
return NULL;
}
func_destroy回收,这个不做太多解释
func_open_video_decoder主要职责是打开视频解码器
func_open_audio_output打开音频输出
func_init_video_decoder打开视频解码器
func_config_video_decoder配置视频解码器
这几个接口,后面再进行详细解释