本人在做网络摄像头的时候遇到的一个需求就是要做一个手机app能够实时看rtsp流传过来的视频,首先当然是用MediaPlayer去播放视频,结果是延时的要命,自己写一个播放器框架也是不实际的,只好上网找框架,发现了这个来源于B站的开源播放框架Ijkplyer。发现网上有许多前辈做过,于是今天总结一下这几天遇到的问题。
从源码可以看出 ijkplayer是一个基于FFmpeg封装的Android/iOS视频播放器。而FFmpeg不用说,能够解码,编码, 转码,复用,解复用,流,过滤器和播放大部分的视频格式。它提供了录制、转换以及流化音视频的完整解决方案。
Android集成Ijkplyer的方法有两种:一种是直接在gradle里面直接设置引用。
dependencies {
# required, enough for most devices.
compile 'tv.danmaku.ijk.media:ijkplayer-java:0.6.1'
compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.6.1'
# Other ABIs: optional
compile 'tv.danmaku.ijk.media:ijkplayer-armv5:0.6.1'
compile 'tv.danmaku.ijk.media:ijkplayer-arm64:0.6.1'
compile 'tv.danmaku.ijk.media:ijkplayer-x86:0.6.1'
compile 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.6.1'
# ExoPlayer as IMediaPlayer: optional, experimental
compile 'tv.danmaku.ijk.media:ijkplayer-exo:0.6.1'
}
其中版本号可以去看github上的具体分支号 https://github.com/Bilibili/ijkplayer
我没有测试使用过这种方法,所以就不误导大家了(PS:使用依赖包有些视频格式和音频格式它不支持,所以要自己编译)
编译的要求是需要在Linux下编译,所以我搭建了一个虚拟机的Ubuntu环境,以下是要下载的一些东西
sudo apt-get install git
sudo apt-get install yasm
git 好从github下载分支。 Yasm的官网翻译解释是 :一个完全重写的NASM汇编。目前,它支持x86和AMD64指令集,接受NASM和气体汇编语法,产出二进制, ELF32 , ELF64 , COFF , Mach - O的( 32和64 ) , RDOFF2 ,的Win32和Win64对象的格式,并生成STABS 调试信息的来源,DWARF 2 ,CodeView 8格式。
接下来就是安装Android的SDK和NDK,我遇到的一个坑就是版本问题,所以如果编译报错提示需要ndk10的可能就是你的NDK版本过高。NDK和SDK的安装都比较简单,要么用sudo apt-get intsall 去下载安装,要么就去官网下载zip,解压配置路径。我都是下载zip安装环境的。
首先是SDK,我从官网下载linux版本的sdk,android-sdk_r24.4.1-linux.tgz,下载解压到一个目录下,配置环境
export ANDROID_SDK_HOME=/home/xiuwenwang/android-sdk-linux
export PATH=$PATH:${ANDROID_SDK_HOME}/tools
export PATH=$PATH:${ANDROID_SDK_HOME}/platforms
路径注意改成自己的,而且tools和platforms有的时候文件夹名字不一样,注意看一下自己的文件夹名字
再是NDK,ndk版本太高会报错,我是从git上下载的
wget -c http://dl.google.com/android/ndk/android-ndk-r10e-linux-x86_64.bin
chmod 777 android-ndk-r10e-linux-x86_64.bin
./android-ndk-r10e-linux-x86_64.bin
(11.29 补充一点:后来发现不用费劲心思的去下相应的版本,去他检测版本的sh脚本修改就可以了,发现报错时
You need the NDKr10e or later ,找到do-detect-env.sh 脚本,修改里面的第78行 11*|12*|13*|14*),就是添加你所用的NDK版本好,如果NDK升级变动不是很大,都没问题)
如果不给权限运行生成的文件夹是不能访问的,设置路径
export NDK=/home/xiuwenwang/android-ndk-r10e
ANDROID_NDK=/home/xiuwenwang/android-ndk-r10e
export ANDROID_NDK
export PATH=${PATH}:$NDK
当然注意要改成你自己的路径
输入以下命令下载,也可以手动去官网下载
git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-android
cd ijkplayer-android
初始化android
./init-android.sh
这里会去下载重要的FFMPEG源码,要花点时间
编译脚本配置
默认的FFmpeg编译选项在文件夹config/module.sh里面,这个是默认编译整个ffmpeg库,我做的项目不需要支持所有的音视频格式,所以改用module-lite.sh文件里的配置,当然要像支持某些功能就要自己添加了。查看config/module-lite.sh文件,里面的enable和disable还是能看懂的吧,接下来就是要添加自己需要的部分,我的要支持rtsp ,h264,g711u,就往上面添加没有的部分
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=pcm_alaw"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=pcm_mulaw"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=mjpeg"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=rtsp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=mjpeg"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=tcp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=udp"
要是不知道添加的格式的名字怎么看,可以去ffmpeg里面的ffmpeg_condecs.txt查找相对应的名称。修改完之后执行
rm module.sh
ln -s module-lite.sh module.sh
source module.sh
这里说一下我在后期测试的时候发现会视频卡顿比较严重,一旦网络情况不好,需要修改一下ffmpeg的源码,找到ff_ffplay.c修改里面的源码,改成如下
//修改后的函数
static int packet_queue_get_or_buffering(FFPlayer *ffp, PacketQueue *q, AVPacket *pkt, int *serial, int finished)
{
while (1) {
int new_packet = packet_queue_get(q, pkt, 1, serial);
if (new_packet < 0)
{
new_packet = packet_queue_get(q, pkt, 0, serial);
if(new_packet < 0)
return -1;
}
else if (new_packet == 0) {
if (!finished)
ffp_toggle_buffering(ffp, 1);
new_packet = packet_queue_get(q, pkt, 1, serial);
if (new_packet < 0)
return -1;
}
if (finished == *serial) {
av_free_packet(pkt);
continue;
}
else
break;
}
return 1;
}
这个修改原因是原函数的队列要一直等待buffer满才会推数据,而网络一旦波动导致丢包就会卡顿。
初始化android支持Https 如果要支持HTTPS就要下载openssl相关的代码,cd到目录ijkplayer-android下,执行
./init-android-openssl.sh
这里就会下载openssl的有关代码,需要耐心等待。之后进入目录ijkplayer-android/android/contrib,执行
./compile-openssl.sh clean
./compile-ffmpeg.sh clean
./compile-openssl.sh all
./compile-ffmpeg.sh all
最后编译ijkplayer ,不加all 只会默认生成armeabi-v7a平台的
cd ..
./compile-ijk.sh all
这样在当前路径下就会生成一个Ijkplayer的文件夹,里面是不同平台的so库和官方给的demo。
build.gradle gradlew.bat ijkplayer-example ijkplayer-x86_64
gradle ijkplayer-arm64 ijkplayer-exo settings.gradle
gradle.properties ijkplayer-armv5 ijkplayer-java tools
gradlew ijkplayer-armv7a ijkplayer-x86
其中ijkplayer-java封装了对应的JNI接口,而example这是在上面又自己封装了一个播放类。如果自己想封装的可以看一下example里面的例子。
到这里so库就编译完成了,那么关于如何调用ijkplayer请看我的下一篇文章。PS,这是我自己编译时经历的各种改动,有限步骤你可能并不需要,参考GitHub上的是最简单的操作,我这里就是给一个如何修改的参考方案。