咸鱼

咸鱼是以盐腌渍后,晒干的鱼

0%

Ubuntu 编译 ijplayer

由于项目【ijkplayer】提供编译好的库没有支持RTSP,而ijkplayer这个项目比较强大之处就是可以根据需要进行裁剪编译,所以我要自己编译一次Android版本,开启RTSP协议。

一、软件环境

  1. Ubuntu16.04 Server
  2. Android SDK
  3. NDK(不要安装最新的版本,14b版本能用)和cmake
  4. ijkplayer-k0.8.8 (commit cced91e3ae3730f5c63f3605b00d25eafcf5b97b)
  5. 其他一些编译c的环境,系统本身就有,就不一样列出。

编译所需软件大概有这些,引用参考文章的

1
2
$ sudo apt install vim openssh-server git curl wget tar unzip
$ sudo apt install build-essential openjdk-8-jdk yasm python

二、配置环境变量

参考[【Android Linux命令行环境变量配置】](../../Android/Android Linux命令行环境变量配置) ,配置:

  • android sdk
  • android ndk
  • java

三、下载ijplayer源码

1
2
3
4
$ git clone https://github.com/bilibili/ijkplayer.git

#加速
$ git clone https://github.com.cnpmjs.org/bilibili/ijkplayer.git

四、初始化

先编辑 init_android.shinit-android-libyuv.shinit-android-libyuv.shinit-android-soundtouch.sh脚本,修改’github.com’ 为 ‘github.com.cnpmjs.org’,否则很慢,下载不了。
如:

1
2
3
4
5
#IJK_FFMPEG_UPSTREAM=https://github.com/Bilibili/FFmpeg.git
#IJK_FFMPEG_FORK=https://github.com/Bilibili/FFmpeg.git

IJK_FFMPEG_UPSTREAM=https://github.com.cnpmjs.org/Bilibili/FFmpeg.git
IJK_FFMPEG_FORK=https://github.com.cnpmjs.org/Bilibili/FFmpeg.git

【修改的commit的代码】

执行

1
$ ./init_android.sh

五、修改配置

1
$ vim config/module-lite.sh

默认支持的协议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocols"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=async"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=bluray"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=concat"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=crypto"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=ffrtmpcrypt"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=ffrtmphttp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=gopher"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=icecast"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=librtmp*"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=libssh"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=md5"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=mmsh"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=mmst"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=rtmp*"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtmp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtmpt"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=rtp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=sctp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=srtp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=subfile"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=unix"

注释行

1
#export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-protocol=rtp"

加入行:RTSP协议

1
2
3
4
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=rtp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=rtsp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-protocol=tcp"
export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --enable-demuxer=sdp"

【commit代码】

替换module

1
2
3
4
$ cd config/
$ cp module.sh module.sh.bak
$ rm module.sh
$ ln -s module-lite.sh module.sh

六、开始编译

  1. 编译ffmpeg(耗时较长)

    1
    2
    3
    $ cd ijkplayer/android/contrib
    $ ./compile-ffmpeg.sh clean
    $ ./compile-ffmpeg.sh all
  2. 编译jikplayer

    1
    $ ./compile-ijk.sh all
  3. 成功
    so文件,在项目的libs目录下,如果是开发机上编译,可以直接用Android Studio打开编译后的example项目。
    由于我是在服务器上编译,所以,我要下载编译好的so文件,如armv7a,路径是:ijkplayer/android/ijkplayer/ijkplayer-armv7a/src/main/libs

  4. 拷贝so文件

    将所有平台的文件都拷贝到 /data/ijk-libs-file 目录下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $ cd ijkplayer/android/ijkplayer
    $ ls
    build.gradle gradle.properties ijkplayer-arm64 ijkplayer-example ijkplayer-x86 tools
    cp-libs.sh gradlew ijkplayer-armv5 ijkplayer-exo ijkplayer-x86_64
    gradle gradlew.bat ijkplayer-armv7a ijkplayer-java settings.gradle

    $ cp -r ijkplayer-armv5/src/main/libs/armeabi/ /data/ijk-libs-file
    $ cp -r ijkplayer-arm64/src/main/libs/arme64 /data/ijk-libs-file
    $ cp -r ijkplayer-armv7a/src/main/libs/armeabi-v7a/ /data/ijk-libs-file
    $ cp -r ijkplayer-x86/src/main/libs/x86/ /data/ijk-libs-file
    $ cp -r ijkplayer-x86_64/src/main/libs/x86_64/ /data/ijk-libs-file

七、错误和解决

  1. NDK版本问题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    $ sh compile-ffmpeg.sh clean
    $ sh compile-ffmpeg.sh all
    ====================
    [*] check archs
    ====================
    FF_ALL_ARCHS = armv5 armv7a arm64 x86 x86_64
    FF_ACT_ARCHS = armv5 armv7a arm64 x86 x86_64

    ====================
    [*] check env armv5
    ====================
    FF_ARCH=armv5
    FF_BUILD_OPT=

    --------------------
    [*] make NDK standalone toolchain
    --------------------
    build on Linux x86_64
    ANDROID_NDK=/usr/local/androidsdk/ndk/21.3.6528147
    IJK_NDK_REL=21.3.6528147
    You need the NDKr10e or later



    #要求NDK版本大于10,但这里是21。
    vim android/contrib$ vim tools/do-detect-env.sh

    # 71行加入: |21*
    70 case "$IJK_NDK_REL" in
    71 11*|12*|13*|14*|21*)

    重新编译可以跳过这个错误,但是出现 “ERROR: Failed to create toolchain.”,还是老老实实把NDK版本改为 12/13/14其中一个吧。
    【下载链接:Android NDK,修订版 14b(2017 年 3 月)Linux 64 位 (x86)】

  2. Android 11 64位真机播放网络视频闪退
    问题
    在64位Android11机器上播放网络视频闪退,本地视频不会闪退,模拟器不会闪退。
    原因
    【ijkplayer issues/5206】里的开发者分析了,是ffmpeg库ff_ffplay.c里面触发了以上Android11的标志问题。
    【Android 11 适配问题】:从 Android 11 开始,对于 64 位进程,所有堆分配都具有一个由实现定义的标记,该标记在具有对 ARM Top-byte Ignore (TBI) 的内核支持的设备上的指针顶部字节中设置。在回收期间检查该标记时,任何修改此标记的应用都会被终止。对于未来支持 ARM 内存标记扩展 (MTE) 的硬件来说,这是必需的。
    缓解办法
    AndroidManifest.xml 文件中添加以下内容:
    <application android:allowNativeHeapPointerTagging="false">
    彻底解决办法
    要彻底解决这个问题,得解决改ffmpeg的ff_ffplay.c,不过ijkplayer的开发者已经修复这个问题,我们升级一下ffmpeg的版本即可,参考下一节【升级FFmpeg4.0】。

八、升级FFmpeg4.0

  1. 修改ffmpeg版本
    1
    2
    3
    4
    5
    6
    7
    $ vim ijkplayer/init-android.sh

    IJK_FFMPEG_COMMIT=ff4.0--ijk0.8.8--20210426--001
    #IJK_FFMPEG_COMMIT=ff3.4--ijk0.8.7--20180103--001

    # 下载新版本源码
    $ ./init_android.sh
    版本改为ff4.0--ijk0.8.8--20210426--001,即4.0版,参考【issues/5290】
  2. 修改编译ffmpeg的配置
    如果现在编译,肯定报错,由于4.0版本有些东西已经丢弃,所以裁剪的配置文件要变动。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $ vim ijkplayer/config/module-lite.sh

    # 注释这两行,否则编译会报错
    #export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-ffserver"
    #export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-vda"

    # 注释掉以上两项,编译还会出现以下错误:
    # ijkplayer/android/contrib/ffmpeg-arm64/libavcodec/eac3_core_bsf.c:39: undefined reference to `ff_ac3_parse_header'
    # ijkplayer/android/contrib/ffmpeg-arm64/libavcodec/eac3_core_bsf.c:55: undefined reference to `ff_ac3_parse_header'

    # 还需加入以下这一行
    export COMMON_FF_CFG_FLAGS="$COMMON_FF_CFG_FLAGS --disable-bsf=eac3_core"
    # 这一行的位置一开始随便放在文件头,结果编译一直没过
    # 移到 `./configure --list-bsf` 这个位置,编译就OK。
    这个问题是参考【【ijkplayer issues/4772】
  3. 重新编译
    1
    2
    3
    4
    5
    6
    $ cd ijkplayer/android/contrib
    $ ./compile-ffmpeg.sh clean
    $ ./compile-ffmpeg.sh all
    $ cd ../
    $ ./compile-ijk.sh clean
    $ ./compile-ijk.sh all

九、参考

【Ubuntu 18.04 编译 ijkplayer】