目录

简要

流程图

代码分析

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<IjkMediaPlayer>(this));
}

initPlayer主要分三大部分:so库加载及初始化,创建Looper线程,so库setup,下面分步介绍
1)so库加载及初始化
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;

}
2)创建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;
}
创建Looper线程,这部分不做太多解释

3)so相关操作setup
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配置视频解码器

这几个接口,后面再进行详细解释

initPlayer初始化过程(一)相关推荐

  1. hadoop作业初始化过程详解(源码分析第三篇)

    (一)概述 我们在上一篇blog已经详细的分析了一个作业从用户输入提交命令到到达JobTracker之前的各个过程.在作业到达JobTracker之后初始化之前,JobTracker会通过submit ...

  2. 操作系统学习:进程、线程与Linux0.12初始化过程概述

    本文参考书籍 1.操作系统真相还原 2.Linux内核完全剖析:基于0.12内核 3.x86汇编语言 从实模式到保护模式 ps:基于x86硬件的pc系统 进程 进程是一种控制流集合,集合中至少包含一条 ...

  3. 超详细解读ORB-SLAM3 单目初始化过程(上篇)

    学习ORB-SLAM3单目视觉SLAM中,发现有很多知识点需要展开和深入,同时又需要对系统有整体的认知,为了强化记忆,记录该系列笔记,为自己图方便,也希望对大家有所启发. 因为知识有限,因此先记录初始 ...

  4. [Spring 深度解析]第7章 IoC容器的初始化过程

    7. IoC容器的初始化过程 ​ 简单来说,IoC容器的初始化是由前面介绍的refresh()方法来启动的,这个方法标志着IoC容器的正式启动.具体来说,这个启动包括BeanDefinition的Re ...

  5. nginx的启动初始化过程(一)

    nginx的启动初始化在src/core/nginx.c的main函数中完成,也是整个nginx的入口.nginx的初始化主要围绕一个类型为ngx_cycle_t的全局变量ngx_cycle展开. m ...

  6. 解析 Java 类和对象的初始化过程 由一个单态模式引出的问题谈起

    在 IBM Bluemix 云平台上开发并部署您的下一个应用. 开始您的试用 问题引入 近日我在调试一个枚举类型的解析器程序,该解析器是将数据库内一万多条枚举代码装载到缓存中,为了实现快速定位枚举代码 ...

  7. 不可逆的类初始化过程

    类的加载过程说复杂很复杂,说简单也简单,说复杂是因为细节很多,比如说今天要说的这个,可能很多人都不了解:说简单,大致都知道类加载有这么几个阶段,loaded->linked->initia ...

  8. android kernel控制台初始化过程

    对于我们的android平台,控制台被定义到了串口1上,因此初始化过程就是把控制台的输出配置到串口1上 对kernel控制台初始化是在挂载文件系统之前,由于没有串口的设备文件,不能通过打开设备文件来访 ...

  9. Mybatis源码解析之Mybatis初始化过程

    一.搭建一个简单的Mybatis工程 为了了解Mybatis的初始化过程,这里需要搭建一个简单的Mybatis工程操作数据库,工程结构如下: 一个UserBean.java private int i ...

最新文章

  1. [Codeforces1137D]Cooperative Game
  2. matlab 基础知识class lt; superclass_name
  3. WPF之复杂形状控件
  4. 【收藏】严重影响IDEA启动速度的插件
  5. 关于数据精度的一些事
  6. php编程 第一节,PHP第一节php简介_PHP
  7. 解决SwipeRefreshLayout与Banner滑动冲突
  8. 2022年企业微信生态研究报告
  9. 首尾相接数组求子数组最大和
  10. docker-compose安装镜像
  11. VUE3.x(v-model)数据双向绑定指令
  12. 一种C/S架构下的 RSA + AES 组合加密方案业务流程
  13. python revit二次开发_Revit怎么二次开发?Revit开发问题汇总
  14. 帝国CMS-后台管理工具
  15. 使用idea导出数据库脚本
  16. html 判断输入的是手机号码,用js验证手机号码格式是否正确
  17. 网易云音乐评论抓取(js逆向)
  18. DTM、DEM、DSM与DOM的概念
  19. [Contrastive Learning] Improving Contrastive Learning by Visualizing Feature Transformation
  20. 抖音推出放映厅,可以免费看电影追剧

热门文章

  1. 用的最多的正则表达式
  2. vs2017编写模板类出现以下错误时:没有与参数列表匹配的构造函数……
  3. linux 高并发文件实时同步,Linux海量数据高并发实时同步架构方案杂谈
  4. 卡尔曼滤波对gps轨迹数据清洗_基于GPS的智能交通系统车辆定位精度提升技术
  5. html登陆l判断,html作业登陆界面
  6. 报错日常——Tomcat45秒超时问题
  7. project不显示里程碑标志_3万台!纽荷兰大方捆打捆机再创全新里程碑
  8. 【NLP】毕设学习笔记(二)transformer
  9. java命令行参数_Java学习从入门到精通,JDK工具条知识点学习资料
  10. jqueryvar语句_你真的掌握变量和类型了吗