根据我们的之前的老方法,采用结构化的方式来对IJKPlayer源码做个分析,首先,我们从整体的角度先把IJKPlayer的整体架构和流程讲下,让大家先有个整体的印象。
本地JNI入口
在Android环境下,JVM层载入一个本地so库流程大致如下:
所以,我们的切入点就从JNI_OnLoad开始,看看和JAVA层交互都有那些方法,以及JAVA层和本地层对接的类是什么。
其so库的加载和退出思维导图如下:
其实主要就是初始化全局的一些环境,比如加载FFMepg的音视频数据解码库、封装格式解码库以及一些全局锁对象等。
IJKPlayer播放整体流程
首先我们先说下IJKPlayer播放视频涉及到的关键技术。
- 底层采用FFMpeg开源框架来进行音视频的解码(包括封装格式和数据);
- 在音视频解码这块IJKPlayer实现自己的部分逻辑,比如在Android支持硬解码(采用MediaCodec完成);
- 在Android环境下,视频的播放支持Opengl ES进行视频渲染;
因此,要完全看懂其源码和逻辑,需要的知识点还是比较多,不如Opengl ES、Android的硬编硬解码、FFMpeg框架原理,最后还需要弄懂基本的图像和音频知识,其它诸如常用的封装格式(比如.flv、.mp4等)、音视频的一些编解码知识(H264、AAC、PCM等)也要掌握,这样,阅读其源码才比较容易。
可见,很多时候我们了解某个东西,其知识可能不在东西本身,而在此东西之外。
废话不多说,我们先看看IJKPlayer的播放整体流程。
IjkMediaPlayer_native_setup:
功能:完成IJK播放环境的初始化,创建IjkMediaPlayer本地结构对象,然后初始化平台相关的解码器和音视频的处理例程,同时,把IjkMediaPlayer保存到JAVA端对应类的_mNativeMediaPlayer成员变量(类型为long),JAVA端类的弱引用保存到IjkMediaPlayer的成员weak_thiz(类型为void*),到这里,就把JAVA端的播放类和本地播放结构互相对应起来。
注意,本地和JAVA端这种映射关系只有调用IjkMediaPlayer_release才会解除。