1. 背景

目前在做音视频相关的工作,在项目中用到了播放相关的问题,使用的框架是GSYVideoPlayer,使用它的原因是可以很方便的切换播放器内核,系统内核、IJKPlayer内核亦或是exo2Player内核,视频播放的格式不统一,使用这种方式能够更大程度的方便开发工作。

为什么要重新编译IJK播放器源码呢?

这次是需要做android9.0的适配,播放的视频格式是rtsp,使用的内核是系统内核(MediaPlayer + Surface),问题是这种方式在4.4的机顶盒(android设备)上播放完全没有问题,在9.0的盒子上出现 有声音无画面 的情况,因为本地没有测试条件,索性我就将内核切换成IJK的内核,在9.0和4.4的盒子上都会出现 有画面没声音 的情况,4.4的设备手上刚好有,这样复现了问题,就方便调试了。
 

2. 设置IJK参数

VideoOptionModel videoOptionMode0l = new VideoOptionModel(1, "analyzemaxduration", 5 * 1000);
	VideoOptionModel videoOptionMode02 = new VideoOptionModel(1, "probesize", 2048 *100);
	VideoOptionModel videoOptionMode03 = new VideoOptionModel(1, "flush_packets", 1);
	VideoOptionModel videoOptionMode04 = new VideoOptionModel(4, "packet-buffering", 0);
	VideoOptionModel videoOptionMode05 = new VideoOptionModel(4, "framedrop", 1);
	VideoOptionModel videoOptionMode06 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1);
	VideoOptionModel videoOptionMode07 = new VideoOptionModel(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "rtsp_transport", "tcp");

3. 遇到的问题

04-26 19:17:27.618 18813-20950/? D/IJKMEDIA: Probe buffer size limit of 204800 bytes reached
04-26 19:17:27.618 18813-20950/? W/IJKMEDIA: Stream #0: not enough frames to estimate rate; consider increasing probesize
04-26 19:17:27.618 18813-20950/? V/IJKMEDIA: stream 0: start_time: 0.000 duration: 171.240
04-26 19:17:27.618 18813-20950/? V/IJKMEDIA: stream 1: start_time: 0.000 duration: 171.240
04-26 19:17:27.618 18813-20950/? V/IJKMEDIA: format: start_time: 0.000 duration: 171.240 bitrate=0 kb/s

W/IJKMEDIA: Could not find codec parameters for stream 1 (Audio: aac ([15][0][0][0] / 0x000F), 0 channels): unspecified sample format

W/IJKMEDIA: Could not find codec parameters for stream 1 (Audio: mp3 ([15][0][0][0] / 0x000F), 0 channels): unspecified sample format

W/IJKMEDIA: Could not find codec parameters for stream 1 (Audio: mp2 ([15][0][0][0] / 0x000F), 0 channels): unspecified sample format

大概意思是 probesize 这个buffSize设置的太小了,需要增大,然后增加一倍之后还是不行,因为看别人设置10240就够了,意识到可能不是参数的问题,有可能是不支持这种音频解码,需要重新编译IJK的源码,使其支持音频解码就行了。

IJK当时可能是出于so大小的考虑,并没有支持所有的格式,只是支持了常见的视频、音频格式,我后来试了一下最大的so编译出来有8M+。

4. 编译IJK源码

4.1 环境准备

4.1.1 一台linux的虚拟机(之前编译过android系统源码,拿来直接用,建议android开发常备一台,说不定啥时候就用到了)

4.1.2 配置好androidSDK环境,配置好NDK环境(推荐ndk-r13b,别问为什么)下载地址:https://developer.android.google.cn/ndk/downloads/

4.1.3 打开终端命令,安装需要的程序

sudo apt-get install git
sudo apt-get install yasm

4.2 IJK源码下载

我用的是最新的版本,所以直接下载主线的版本就好了:

git clone https://github.com/bilibili/ijkplayer.git

4.3 初始化FFMPEG(可能会比较耗时,或网络连接超时,看后面的解决办法)

./init-android.sh

4.4 初始化openSSL(可选,如果要支持https的必选)

./init-android-openssl.sh

4.5 修改配置文件,支持更多的编码格式

进入config目录,有4个.sh文件:

1. 如果要更多的编码格式,就将module.sh删了,将module-default.sh重命名为module.sh

2. 如果要更小的,或者少量的编码格式(hevc),可以使用module-lite-hevc.sh,操作同上

3. 如果不使用hevc的,可以使用module-lite.sh,操作同上

4.6 编译

cd到android/contrib下,执行清除命令,然后编译需要的so,这里的all是生成所有版本的。

如果只需要对应版本的,可以把all替换成armv7a等你需要的版本,也可以把你不需要的cpu框架从配置文件中删除。

./compile-openssl.sh clean//清除 (可选)
./compile-openssl.sh all//编译 (可选)

./compile-ffmpeg.sh clean//清除
./compile-ffmpeg.sh all//编译

4.7 生成so文件(我使用的是armv7a)

切换到上一级android目录执行:

./compile-ijk.sh all

至此so文件就生成了,路径是:android/ijkplayer/ijkplayer-armv7a/src/main/libs/。

4.8 使用

将生成的so放入项目的libs目录下,并且在在项目的build.gradle中android标签下添加以下配置:

sourceSets{
	main{
		jniLibs.srcDirs=['libs']
	}
}

这样就会使用libs下面的so文件,而不会使用你依赖的库的so文件。

到此编译使用的流程就介绍完了。

5. 过程中遇到的问题

5.1 Failed to connect to github.com port 443: Connection refused

因为要从github上下载FFPMEG相关的代码,执行编译语句的时候发现经常会资源下载超时。

5.2 配置环境的时候需要用到vim命令

1、进入需要编辑的文件的所在目录,输入,这里用vi替换vim也可以

	命令:vim 完整文件名

	2、开始编辑文本,点击 i 键进入编辑,此时在窗体最底下会出现— —insert— —

	3、利用方向键移到你需要添加内容的位置,然后输入内容

	4、输入完成后按ESC键退出,这时底部的insert就没有了、

	5、然后保存编辑的文件并退出

	命令: :wq(注意前面有英文冒号)

5.3 linux fatal: unable to access 'https://github.com/Bilibili/libyuv.git/

因为下载的时候,某些某块资源可能会下载失败,所以需要单独执行对应的脚本文件重下,类似的问题都可以执行对应的脚本。

解决办法:切换到根目录执行: ./init-android-libyuv.sh

5.4 修改环境变量

1. 修改环境变量

	vim /etc/profile

2. 添加:
	export ANDROID_NDK=/home/lbs_disk/ijkplayer/android-ndk-r13b
	export PATH=$ANDROID_NDK:$PATH

3. 使环境变量生效:
	source /etc/profile

5.5 编译出so之后,发现大部分的视频播放都没问题有两类视频,依然是报以下错误:

W/IJKMEDIA: Could not find codec parameters for stream 1 (Audio: aac ([15][0][0][0] / 0x000F), 0 channels): unspecified sample format
W/IJKMEDIA: Could not find codec parameters for stream 1 (Audio: mp3 ([15][0][0][0] / 0x000F), 0 channels): unspecified sample format

现在确定了自己编译出来的so已经支持acc和mp3格式了,那应该就是 probesize的设置太小导致的,尝试将当前的参数增加一倍后,所有的视频均可正常播放:

VideoOptionModel videoOptionMode02 = new VideoOptionModel(1, "probesize", 4096 *100);

5.6 遇到播放mpeg2格式的视频播放有声音,但是黑屏

配置文件中增加对应的编码即可:

export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=mpegvideo"

5.7 支持更多格式编码,按需增加,有的可能不识别了,删掉就好

mp3
--enable-libmp3lame 
--enable-decoder=mp3 
--enable-demuxer=mp3 
--enable-muxer=mp3
--enable-encoder=libmp3lame
支持vorbis
--enable-libvorbis 
--enable-parser=vorbis 
--enable-encoder=vorbis 
--enable-decoder=vorbis 
--enable-encoder=libvorbis 
--enable-decoder=libvorbis 
--enable-muxer=ogg
--enable-demuxer=ogg
支持wav
--enable-libwavpack
--enable-muxer=wav
--enable-demuxer=wav
--enable-decoder=wavpack
--enable-encoder=wavpack
--enable-decoder=wav
--enable-encoder=wav
--enable-encoder=pcm_s16le
--enable-decoder=pcm_s16le

--enable-encoder=pcm_u8
--enable-decoder=pcm_u8
--enable-muxer=pcm_u8
--enable-demuxer=pcm_u8  
支持aac

export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-libvo-aacenc"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-libfdk_aac"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-libfaac"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-parser=aac"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-encoder=aac"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=aac"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-encoder=libfaac"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-encoder=libvo_aacenc"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-encoder=libaacplus"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-encoder=libfdk_aac"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=libfdk_aac"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=aac"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-muxer=adts"
支持mp2
# for mp2
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-encoder=mp2"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=mp2 "
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-muxer=mp2"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-decoder=mp2float"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-encoder=mp2fixed"
flac 支持
--enable-encoder=flac
--enable-decoder=flac
--enable-demuxer=flac
--enable-muxer=flac
--enable-parser=flac
jpeg等
--enable-encoder=jpeg2000 
--enable-encoder=mjpeg 
--enable-encoder=ljpeg 
--enable-encoder=jpegls
--enable-decoder=jpeg2000 
--enable-decoder=jpegls 
--enable-decoder=mjpeg 
--enable-decoder=mjpegb 
--enable-muxer=mjpeg 
--enable-demuxer=mjpeg 
--enable-encoder=png 
--enable-decoder=png 
--enable-parser=png 
添加scale的支持
--enable-swscale 
--enable-swscale-alpha 
--enable-filter=scale 
ac3
--enable-encoder=ac3 
--enable-decoder=ac3 
--enable-encoder=ac3_fixed
--enable-decoder=atrac3 
--enable-decoder=atrac3p 
--enable-encoder=eac3 
--enable-decoder=eac3 
--enable-muxer=ac3 
--enable-demuxer=ac3 
--enable-muxer=eac3 
--enable-demuxer=eac3 
支持wma/wmv
--enable-decoder=wmalossless 
--enable-decoder=wmapro 
--enable-encoder=wmav1 
--enable-decoder=wmav1 
--enable-encoder=wmav2 
--enable-decoder=wmav2 
--enable-decoder=wmavoice 
--enable-demuxer=xwma 
--enable-demuxer=avi 
--enable-muxer=avi 
--enable-demuxer=asf 
--enable-muxer=asf 
--enable-encoder=wmv1
--enable-decoder=wmv1 
--enable-encoder=wmv2 
--enable-decoder=wmv2 
--enable-decoder=wmv3 
--enable-decoder=wmv3_crystalhd 
--enable-decoder=wmv3_vdpau 
--enable-decoder=wmv3image

6. 参考资料

6.1. 重编译支持https:https://github.com/CarGuo/GSYVideoPlayer/blob/master/doc/BUILD_SO.md
6.2. 拓展ijk支持的so:https://github.com/CarGuo/GSYVideoPlayer/blob/master/doc/DECODERS.md