编译Android Ijkplayer以及问题
一、Linux 环境安装的程序
下载:
-
git
yum install git
-
yasm
yum install yasm
-
ndk
下载ndk ,推荐ndk 14 以上的
配置环境变量
配置ndk、sdk (交叉编译时需要查找头文件和库文件),打开/etc/profile 文件
vim /etc/profile
在文件末尾加上
export ANDROID_SDK=你的SDF安装路径
export ANDROID_NDK=/root/ndk/android-ndk-r14b
NDK 的安装路径,使用14版本以上的会出问题,问题分析在后面,虽然能改,但是不太清楚内部有什么限制,所有还是老实的用14版本的
保存,然后执行 source /etc/profile 刷新环境变量
二、下载ijkplayer
git官网上的Build Android
git clone https://github.com/Bilibili/ijkplayer.git ijkplayer-android
cd ijkplayer-android
git checkout -B latest k0.8.8
./init-android.sh
cd android/contrib
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh all
cd ..
./compile-ijk.sh all
github 下载慢,可以在码云上搜ijkplayer,然后下载下来,这里提供一个地址
git clone https://gitee.com/mirrors/ijkplayer.git ijkplayer-android
切换到最新分支:
git checkout -B latest k0.8.8
先不要执行 ./init-android.sh,如果你播放器需要支持rtp、tcp、rtsp等(具体自行谷歌),需要修改配置文件,如果不需要修改,跳过下面的步骤1
1、 config 目录性有四个文件
三个module-...开头的文件就是配置文件,其实里面就是定义一些变量(如下图),用于开启或关闭支持库,默认使用的module-default.sh,如果能看懂就可以自行开启或者关闭,看不懂就老实用module-default.sh
其中module.sh 文件可以理解为指向其他文件的文件,编译时,脚本文件不清楚你使用三个配置文件的哪个文件,所以使用linux 命令
ln -s module-default.sh module.sh
来指定module.sh 链接到module-default.sh文件,当然也可以
ln -s module-lite-hevc.sh module.sh
ln -s module-lite.sh module.sh
来链接到其他文件,反正脚本文件执行时执行的是module.sh脚本文件
2、 如果直接执行 init-android.sh 文件,会从github 上拉取 armv5 、armv7、arm64、x86、x86_64 架构的源码,这里我只需要armv7a 的,所有其他的都关了,如果需要可以自行打开
#IJK_FFMPEG_UPSTREAM=https://github.com/Bilibili/FFmpeg.git
#IJK_FFMPEG_FORK=https://github.com/Bilibili/FFmpeg.git
IJK_FFMPEG_UPSTREAM=https://gitee.com/yuazhen/FFmpeg.git
IJK_FFMPEG_FORK=https://gitee.com/yuazhen/FFmpeg.git
IJK_FFMPEG_COMMIT=ff3.4--ijk0.8.7--20180103--001
IJK_FFMPEG_LOCAL_REPO=extra/ffmpeg
set -e
TOOLS=tools
git --version
echo "== pull ffmpeg base =="
sh $TOOLS/pull-repo-base.sh $IJK_FFMPEG_UPSTREAM $IJK_FFMPEG_LOCAL_REPO
function pull_fork()
{
echo "== pull ffmpeg fork $1 =="
sh $TOOLS/pull-repo-ref.sh $IJK_FFMPEG_FORK android/contrib/ffmpeg-$1 ${IJK_FFMPEG_LOCAL_REPO}
cd android/contrib/ffmpeg-$1
git checkout ${IJK_FFMPEG_COMMIT} -B ijkplayer
cd -
}
#pull_fork "armv5"
pull_fork "armv7a"
#pull_fork "arm64"
#pull_fork "x86"
#pull_fork "x86_64"
./init-config.sh
./init-android-libyuv.sh
./init-android-soundtouch.sh
因为拉取代码也是在github 上获取的,这里修改了下载源码路径
#IJK_FFMPEG_UPSTREAM=https://github.com/Bilibili/FFmpeg.git
#IJK_FFMPEG_FORK=https://github.com/Bilibili/FFmpeg.git
IJK_FFMPEG_UPSTREAM=https://gitee.com/yuazhen/FFmpeg.git
IJK_FFMPEG_FORK=https://gitee.com/yuazhen/FFmpeg.git
init-android.sh 里面也会去下载libyuv soundtouch库的代码,这两个库不大,所以可以不用修改下载地址,执行 init-android.sh 文件
./init-android.sh
完成后进入到 android/contrib 目录
cd android/contrib
接下来开始编译下载的ffmpeg 库,首先先清理
./compile-ffmpeg.sh clean
因为只下载了armv7a ,编译ffmpeg 不能编译全部,这里只编译 armv7a的(如果是多架构编译看后文)
./compile-ffmpeg.sh armv7a
(这里可能会因为ndk 版本问题编译出错,具体修改看后面问题)
执行完之后 就会在 ../ijkplayer-android/android/contrib/build/ffmpeg-armv7a/output 目录下生成ffmpeg 的头文件和库文件
以上的都是编译ijkplayer 所需要的东西,接下来才是真正编译ijkplayer
这里只下载了armv7a,所有只编译armv7a的
返回上一层目录
cd ..
./compile-ijk.sh armv7a
成功后会在/ijkplayer/ijkplayer-android/android/ijkplayer 目录下对应的cpu 架构生成ijkplayer的动态库文件,so 文件是放在对应架构的 ../src/main/libs/armeabi-v7a
ijkplayer-example 就是示例项目代码
三、编译遇到的问题
1、You need the NDKr10e or later
在执行 ./compile-ffmpeg.sh armv7a 的时候
如果ndk版本大于 14,会报:
以下是分析原因,如果看结果直接略过
打开 comfile-ffmpeg.sh 文件,省略部分,主要内容:
case "$FF_TARGET" in
"")
echo_archs armv7a
sh tools/do-compile-ffmpeg.sh armv7a
;;
#这里这里
armv5|armv7a|arm64|x86|x86_64)
echo_archs $FF_TARGET $FF_TARGET_EXTRA
sh tools/do-compile-ffmpeg.sh $FF_TARGET $FF_TARGET_EXTRA
echo_nextstep_help
;;
.
.
.
.
*)
echo_usage
exit 1
;;
esac
就是感觉传入进来的armv7a 字符匹配 ,然后执行
sh tools/do-compile-ffmpeg.sh $FF_TARGET $FF_TARGET_EXTRA
FF_TARGET 这里是传进来的armv7a
FF_TARGET_EXTRA 这里没传进来,为空
就是执行
sh tools/do-compile-ffmpeg.sh armv7a
又去执行当前目录下tools包下的do-compile-ffmpeg.sh 文件,带个armv7a 参数进去;(真正的编译脚本不是comfile-ffmpeg.sh 而是do-compile-ffmpeg.sh ,所有单个文件也可以直接执行./tools/do-compile-ffmpeg.sh armv7a ,执行的目录还是在compile-ffmpeg.sh文件所在的目录)
do-compile-ffmpeg.sh 内容的开头():
FF_ARCH=$1
FF_BUILD_OPT=$2
echo "FF_ARCH=$FF_ARCH"
echo "FF_BUILD_OPT=$FF_BUILD_OPT"
if [ -z "$FF_ARCH" ]; then
echo "You must specific an architecture 'arm, armv7a, x86, ...'."
echo ""
exit 1
fi
.
.
设置各种变量
.
.
#--------------------
echo ""
echo "--------------------"
echo "[*] make NDK standalone toolchain"
echo "--------------------"
. ./tools/do-detect-env.sh
.
.
.
判断 FF_ARCH 参数是否空,如果为空就输出 "You must specific an architecture 'arm, armv7a, x86, ...'. 然后退出,
这里的 FF_ARCH 就是传进来的armv7a(这里讲废话了),有条命令. ./tools/do-detect-env.sh;
上面都是废话,可以不用看,细节而已,下面才是重要内容
在编译脚本之前会执行do-detect-env.sh 文件检查运行环境和NDK 版本
#! /usr/bin/env bash
set -e
UNAME_S=$(uname -s)
UNAME_SM=$(uname -sm)
echo "build on $UNAME_SM"
echo "ANDROID_NDK=$ANDROID_NDK"
if [ -z "$ANDROID_NDK" ]; then
echo "You must define ANDROID_NDK before starting."
echo "They must point to your NDK directories."
echo ""
exit 1
fi
# try to detect NDK version
export IJK_GCC_VER=4.9
export IJK_GCC_64_VER=4.9
export IJK_MAKE_TOOLCHAIN_FLAGS=
export IJK_MAKE_FLAG=
export IJK_NDK_REL=$(grep -o '^r[0-9]*.*' $ANDROID_NDK/RELEASE.TXT 2>/dev/null | sed 's/[[:space:]]*//g' | cut -b2-)
case "$IJK_NDK_REL" in
10e*)
# we don't use 4.4.3 because it doesn't handle threads correctly.
if test -d ${ANDROID_NDK}/toolchains/arm-linux-androideabi-4.8
# if gcc 4.8 is present, it's there for all the archs (x86, mips, arm)
then
echo "NDKr$IJK_NDK_REL detected"
case "$UNAME_S" in
Darwin)
export IJK_MAKE_TOOLCHAIN_FLAGS="$IJK_MAKE_TOOLCHAIN_FLAGS --system=darwin-x86_64"
;;
CYGWIN_NT-*)
export IJK_MAKE_TOOLCHAIN_FLAGS="$IJK_MAKE_TOOLCHAIN_FLAGS --system=windows-x86_64"
;;
esac
else
echo "You need the NDKr10e or later"
exit 1
fi
;;
*)
IJK_NDK_REL=$(grep -o '^Pkg\.Revision.*=[0-9]*.*' $ANDROID_NDK/source.properties 2>/dev/null | sed 's/[[:space:]]*//g' | cut -d "=" -f 2)
echo "IJK_NDK_REL=$IJK_NDK_REL"
#这里这里这里
case "$IJK_NDK_REL" in
11*|12*|13*|14*)
if test -d ${ANDROID_NDK}/toolchains/arm-linux-androideabi-4.9
then
echo "NDKr$IJK_NDK_REL detected"
else
echo "You need the NDKr10e or later"
exit 1
fi
;;
*)
echo "You need the NDKr10e or later"
exit 1
;;
esac
;;
esac
case "$UNAME_S" in
Darwin)
export IJK_MAKE_FLAG=-j`sysctl -n machdep.cpu.thread_count`
;;
CYGWIN_NT-*)
IJK_WIN_TEMP="$(cygpath -am /tmp)"
export TEMPDIR=$IJK_WIN_TEMP/
echo "Cygwin temp prefix=$IJK_WIN_TEMP/"
;;
esac
export IJK_NDK_REL=$(grep -o '^r[0-9]*.*' $ANDROID_NDK/RELEASE.TXT 2>/dev/null | sed 's/[[:space:]]*//g' | cut -b2-)
使用正则判断NDK的版本
如果NDK 版本是10e的,执行下面的
case "$IJK_NDK_REL" in
10e*)
如果是其他的,执行
case "$IJK_NDK_REL" in
11*|12*|13*|14*) # 这里就是判断NDK 版本是不是11、12、13、14
if test -d ${ANDROID_NDK}/toolchains/arm-linux-androideabi-4.9 #检查对应版本的是否存在
这里只检查了 11*|12*|13*|14*四个版本的,不妨加上 17试试
11*|12*|13*|14*|17*)
保存之后执行 ./compile-ffmpeg.sh armv7a ,接着又报:
因为编译ffmpeg 使用的Android平台默认为 9,arm 平台最低为14,所以在do-comfile-ffmpeg.sh 文件中加入
FF_ANDROID_PLATFORM=android-24 #我这里的sdk 版本为24
.
.
.
#----- armv7a begin -----
if [ "$FF_ARCH" = "armv7a" ]; then
#这里这里
FF_ANDROID_PLATFORM=android-24
FF_BUILD_NAME=ffmpeg-armv7a
FF_BUILD_NAME_OPENSSL=openssl-armv7a
FF_BUILD_NAME_LIBSOXR=libsoxr-armv7a
FF_SOURCE=$FF_BUILD_ROOT/$FF_BUILD_NAME
FF_CROSS_PREFIX=arm-linux-androideabi
FF_TOOLCHAIN_NAME=${FF_CROSS_PREFIX}-${FF_GCC_VER}
FF_CFG_FLAGS="$FF_CFG_FLAGS --arch=arm --cpu=cortex-a8"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-neon"
FF_CFG_FLAGS="$FF_CFG_FLAGS --enable-thumb"
FF_EXTRA_CFLAGS="$FF_EXTRA_CFLAGS -march=armv7-a -mcpu=cortex-a8 -mfpu=vfpv3-d16 -mfloat-abi=softfp -mthumb"
FF_EXTRA_LDFLAGS="$FF_EXTRA_LDFLAGS -Wl,--fix-cortex-a8"
FF_ASSEMBLER_SUB_DIRS="arm"
elif [ "$FF_ARCH" = "armv5" ]; then
.
.
.
保存之后执行 ./compile-ffmpeg.sh armv7a
2、ERROR: Failed to create toolchain
在执行./compile-ffmpeg.sh armv7a 的时候有些系统会保存 Failed to create toolchain
这是因为linux 系统有些使用python版本 是python3(python2的我没试过)
可以使用rpm 命令检查python 版本
rpm -qa | grep python
在执行do-compile-ffmpeg.sh 中会执行 NDK的 $ANDROID_NDK/build/tools/make-standalone-toolchain.sh文件
make-standalone-toolchain.sh 文件最后会运行python 脚本 make_standalone_toolchain.py
PLATFORM_NUMBER=${PLATFORM#android-}
if [ -n "$PLATFORM_NUMBER" ]; then
PLATFORM_ARG="--api $PLATFORM_NUMBER"
else
PLATFORM_ARG=""
fi
#修改前的
#run python `dirname $0`/make_standalone_toolchain.py \
# --arch $ARCH $PLATFORM_ARG --stl $STL $INSTALL_ARG $FORCE_ARG
#修改后的
python3 `dirname $0`/make_standalone_toolchain.py \
--arch $ARCH $PLATFORM_ARG --stl $STL $INSTALL_ARG $FORCE_ARG
fail_panic "Failed to create toolchain."
if [ -n "$INSTALL_DIR" ]; then
dump "Toolchain installed to $INSTALL_DIR."
else
dump "Package installed to $PACKAGE_DIR."
fi
如果是python3 版本就会报错,因为run python 命令运行不了python3的文件(.py),所以把run python改成
python3(python2没试过)
3、./compile-ijk.sh armv7a 报错
在最后关键时刻,使用NDK 14b编译 ijkplayer 竟然不行,就感觉还没拉出来完,中间夹断了那么难受,最后是把NDK 版本改成 17的才可以
四、编译多架构
比如这里需要编译 armv7a 与arm64
首先init-android.sh 必须下载对应架构的源码
function pull_fork()
{
echo "== pull ffmpeg fork $1 =="
sh $TOOLS/pull-repo-ref.sh $IJK_FFMPEG_FORK android/contrib/ffmpeg-$1 ${IJK_FFMPEG_LOCAL_REPO}
cd android/contrib/ffmpeg-$1
git checkout ${IJK_FFMPEG_COMMIT} -B ijkplayer
cd -
}
#pull_fork "armv5"
//下载armv7a 与arm64
pull_fork "armv7a"
pull_fork "arm64"
#pull_fork "x86"
#pull_fork "x86_64"
./init-config.sh
./init-android-libyuv.sh
./init-android-soundtouch.sh
接着修改compile-ffmpeg.sh 文件,FF_ACT_ARCHS_64 只保留armv7a 、arm64
.
.
.
#FF_ACT_ARCHS_32="armv5 armv7a x86"
#FF_ACT_ARCHS_64="armv5 armv7a arm64 x86 x86_64"
#这里是32位于64位,现在一般的都是64位
FF_ACT_ARCHS_32="armv7a"
FF_ACT_ARCHS_64="armv7a arm64"
FF_ACT_ARCHS_ALL=$FF_ACT_ARCHS_64
.
.
.
执行脚本时候使用的就是
./compile-ffmpeg.sh all
同样,接着修改compile-ijk.sh 文件 ACT_ABI_64 只保留armv7a 、arm64
.
.
.
REQUEST_TARGET=$1
REQUEST_SUB_CMD=$2
#ACT_ABI_32="armv5 armv7a x86"
#ACT_ABI_64="armv5 armv7a arm64 x86 x86_64"
ACT_ABI_32="armv7a"
ACT_ABI_64="armv7a arm64"
ACT_ABI_ALL=$ACT_ABI_64
UNAME_S=$(uname -s)
.
.
.
执行脚本时候使用的就是
./compile-ijk.sh all