5.3 IJKplayer框架介绍
IJKplayer是Bilibili网站工程师基于FFmpeg及MediaCodec开发的开源播放器框架,内部实现了软解及硬解的功能,其基本流程如下图所示: 针对各种铺天盖地的播放器项目,我们选取了比较出众的IJKplayer进行源码剖析。它是一个基于FFPlay的轻量级Android/iOS视频播放器,实现了跨平台的功能,API易于集成、编译配置可裁剪、方便控制安装包大小。
结构说明
我们可以在GitHub下载或查看ijkplayer项目,地址是https://github.com/Bilibili/ijkplayer ,可看到其主要目录结构如下:
目录名称 | 说明 |
---|---|
tool | 初始化项目工程脚本 |
config | 编译ffmpeg使用的配置文件 |
extra | 存放编译ijkplayer所需的依赖源文件, 如ffmpeg、openssl等 |
ijkmedia | 核心代码 |
ijkplayer | 播放器数据下载及解码相关 |
ijksdl | 音视频数据渲染相关 |
ios | iOS平台上的上层接口封装以及平台相关方法 |
android | Android平台上的上层接口封装以及平台相关方法 |
下面是在android目录中我们看到的目录和说明
目录名称 | 说明 |
---|---|
ijkplayer-arm64 | arm64下编译出来的.so文件 |
ijkplayer-armv5 | armv5编译出来的.so文件 |
ijkplayer-armv7a | armv7a编译出来的.so文件 |
ijkplayer-x86 | x86编译出来的.so文件 |
ijkplayer-x86_64 | x86_64编译出来的.so文件 |
ijkplayer-exo | google开源的一个新的播放器ExoPlayer,在Demo中和ijkplayer对比用的。通过安装ijkplayer可以发现setting里面可以选择不同player来渲染多媒体显示,该模块下面就是一个MediaPlayer |
ijkplayer-java | ijkplayer的一些操作封装及定义。这里面是通用的API接口,里面最主要的是IMediaPlayer,它是用来渲染显示多媒体的 |
ijkplayer-example | ijkplayer官方提供的示例 |
特性列表
特性名称 | 说明 |
---|---|
Android平台 | 支持API 9〜23 |
CPU | ARMv7a,ARM64v8a,x86(ARMv5未在真实设备上测试) |
API | API提供丰富的方法,易于集成 |
视频输出 | NativeWindow,OpenGL ES 2.0 |
音频输出 | AudioTrack,OpenSL ES |
编解码器 | MediaCodec(API 16+,Android 4.1+),支持硬件加速解码,更加省电 |
其他 | 可替代android.media.MediaPlayer,ExoPlayer |
在功能的具体实现上,iOS和Android平台的差异主要表现在视频硬件解码以及音视频渲染方面,两者实现的载体区别如下表所示:
Platform | Hardware Codec | Video Render | Audio Output |
---|---|---|---|
iOS | VideoToolBox | OpenGL ES | AudioQueue |
Android | MediaCodec | OpenGL ES、MediaCodec | OpenSL ES、AudioTrack |
前期准备
开发前我们先给大家介绍一下,如何编译ijkplayer和ffmpeg。注意大家尽量不要用Windows下编译,各种想象不到编译不通过的Bug,这里我们以在Ubuntu下编译源码为例。首先必须安装需要安装homebrew, git, yasm三个软件,再次注意AndroidNDK必须安装,最好是r10-14版本内,不然编译可能会出错。
# install homebrew, git, yasm
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install git
brew install yasm
# add these lines to your ~/.bash_profile or ~/.profile
# export ANDROID_SDK=<your sdk path>
# export ANDROID_NDK=<your ndk path>
# on Cygwin (unmaintained)
# install git, make, yasm
全部安装完成,在命令行继续一步步执行如下代码
git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-android
cd ijkplayer-android
git checkout -B latest k0.8.4
./init-android.sh
cd android/contrib
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh all
cd ..
./compile-ijk.sh all
如果执行过程中没有任何问题,执行成功后我们可以到android文件夹下ijkplayer下,在对应的cpu项目中找到相应的.so文件了。
简单用法
从官方的example项目来看,用到了很多东西,可是大多数我们都不需要,所以需要去掉一些没用的代码精简一下。exo是Google提供的新的播放器,我们这里不需要直接去掉,需要的只有tv.danmaku.ijk.media.example.widget.media包下的部分类。链接库ijkplayer-arm64,ijkplayer-armv5,ijkplayer-armv7a,ijkplayer-x86,ijkplayer-x86_64是不同体系架构的动态链接库,在工程结构里面作为一个模块,如果项目没用要求做兼容多平台,可以删除其他目录结构,单独保留自己需要的平台目录即可。如果对ijkplayer没用改动的话,也可以在Gradle里直接集成。
# required
allprojects {
repositories {
jcenter()
}
}
dependencies {
# required, enough for most devices.
compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.4'
compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4'
# Other ABIs: optional
compile 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.4'
compile 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.4'
compile 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.4'
compile 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.4'
# ExoPlayer as IMediaPlayer: optional, experimental
compile 'tv.danmaku.ijk.media:ijkplayer-exo:0.8.4'
}
播放的实现方式
在我们项目的布局xml文件中,我们只需加上这个组件即可
<tv.danmaku.ijk.media.widget.media.IjkVideoView
android:id="@+id/ijkPlayer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
然后在activity代码中注册这个组件,并设置其需要的方法
IjkVideoView videoView = (IjkVideoView) findViewById(R.id.video_view);
videoView.setAspectRatio(IRenderView.AR_ASPECT_FIT_PARENT);
String url = "rtmp://192.168.1.92:8080/liveOnline/6666";
videoView.setVideoURI(Uri.parse(url));
videoView.start();
常用的方法用
/**
* 参数aspectRatio(缩放参数)参见IRenderView的常量:
IRenderView.AR_ASPECT_FIT_PARENT,
IRenderView.AR_ASPECT_FILL_PARENT,
IRenderView.AR_ASPECT_WRAP_CONTENT,
IRenderView.AR_MATCH_PARENT,
IRenderView.AR_16_9_FIT_PARENT,
IRenderView.AR_4_3_FIT_PARENT
*/
public void setAspectRatio(int aspectRatio);
//改变视频缩放状态。
public int toggleAspectRatio();
//设置视频路径。
public void setVideoPath(String path);
//设置视频URI。(可以是网络视频地址)
public void setVideoURI(Uri uri);
//停止视频播放,并释放资源。
public void stopPlayback();
/**
* 设置媒体控制器。
* 参数controller:媒体控制器,注意是com.hx.ijkplayer_demo.widget.media.IMediaController。
*/
public void setMediaController(IMediaController controller);
//改变媒体控制器显隐
private void toggleMediaControlsVisiblity();
//注册一个回调函数,在视频预处理完成后调用。在视频预处理完成后被调用。此时视频的宽度、高度、宽高比信息已经获取到,此时可调用seekTo让视频从指定位置开始播放。
public void setOnPreparedListener(OnPreparedListener l);
//播放完成回调
public void setOnCompletionListener(IMediaPlayer.OnCompletionListener l);
//播放错误回调
public void setOnErrorListener(IMediaPlayer.OnErrorListener l);
//事件发生回调
public void setOnInfoListener(IMediaPlayer.OnInfoListener l);
//获取总长度
public int getDuration();
//获取当前播放位置。
public long getCurrentPosition();
//设置播放位置。单位毫秒
public void seekTo(long msec);
//是否正在播放。
public boolean isPlaying();
//获取缓冲百分比。
public int getBufferPercentage();