編譯Android Ijkplayer以及問題
一、Linux 環(huán)境安裝的程序
下載:
-
git
yum install git
-
yasm
yum install yasm
-
ndk
下載ndk 滑蚯,推薦ndk 14 以上的
配置環(huán)境變量
配置ndk矛纹、sdk (交叉編譯時需要查找頭文件和庫文件),打開/etc/profile 文件
vim /etc/profile
在文件末尾加上
export ANDROID_SDK=你的SDF安裝路徑
export ANDROID_NDK=/root/ndk/android-ndk-r14b
NDK 的安裝路徑霜医,使用14版本以上的會出問題齿拂,問題分析在后面,雖然能改支子,但是不太清楚內(nèi)部有什么限制创肥,所有還是老實的用14版本的
保存,然后執(zhí)行 source /etc/profile 刷新環(huán)境變量
二、下載ijkplayer
git官網(wǎng)上的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
先不要執(zhí)行 ./init-android.sh趾代,如果你播放器需要支持rtp贯底、tcp、rtsp等(具體自行谷歌)撒强,需要修改配置文件禽捆,如果不需要修改,跳過下面的步驟1
1飘哨、 config 目錄性有四個文件
三個module-...開頭的文件就是配置文件胚想,其實里面就是定義一些變量(如下圖),用于開啟或關(guān)閉支持庫芽隆,默認使用的module-default.sh浊服,如果能看懂就可以自行開啟或者關(guān)閉,看不懂就老實用module-default.sh
<img src=https://img-blog.csdnimg.cn/202009111614390.png?/>
其中module.sh 文件可以理解為指向其他文件的文件胚吁,編譯時牙躺,腳本文件不清楚你使用三個配置文件的哪個文件,所以使用linux 命令
ln -s module-default.sh module.sh
來指定module.sh 鏈接到module-default.sh文件腕扶,當(dāng)然也可以
ln -s module-lite-hevc.sh module.sh
ln -s module-lite.sh module.sh
來鏈接到其他文件孽拷,反正腳本文件執(zhí)行時執(zhí)行的是module.sh腳本文件
2、 如果直接執(zhí)行 init-android.sh 文件半抱,會從github 上拉取 armv5 脓恕、armv7、arm64代虾、x86进肯、x86_64 架構(gòu)的源碼,這里我只需要armv7a 的棉磨,所有其他的都關(guān)了江掩,如果需要可以自行打開
#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庫的代碼乘瓤,這兩個庫不大环形,所以可以不用修改下載地址,執(zhí)行 init-android.sh 文件
./init-android.sh
完成后進入到 android/contrib 目錄
cd android/contrib
接下來開始編譯下載的ffmpeg 庫衙傀,首先先清理
./compile-ffmpeg.sh clean
因為只下載了armv7a 抬吟,編譯ffmpeg 不能編譯全部,這里只編譯 armv7a的(如果是多架構(gòu)編譯看后文)
./compile-ffmpeg.sh armv7a
(這里可能會因為ndk 版本問題編譯出錯统抬,具體修改看后面問題)
執(zhí)行完之后 就會在 ../ijkplayer-android/android/contrib/build/ffmpeg-armv7a/output 目錄下生成ffmpeg 的頭文件和庫文件
以上的都是編譯ijkplayer 所需要的東西火本,接下來才是真正編譯ijkplayer
這里只下載了armv7a危队,所有只編譯armv7a的
返回上一層目錄
cd ..
./compile-ijk.sh armv7a
成功后會在/ijkplayer/ijkplayer-android/android/ijkplayer 目錄下對應(yīng)的cpu 架構(gòu)生成ijkplayer的動態(tài)庫文件,so 文件是放在對應(yīng)架構(gòu)的 ../src/main/libs/armeabi-v7a
ijkplayer-example 就是示例項目代碼
三钙畔、編譯遇到的問題
1茫陆、You need the NDKr10e or later
在執(zhí)行 ./compile-ffmpeg.sh armv7a 的時候
如果ndk版本大于 14,會報:
以下是分析原因擎析,如果看結(jié)果直接略過
打開 comfile-ffmpeg.sh 文件簿盅,省略部分,主要內(nèi)容:
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 字符匹配 揍魂,然后執(zhí)行
sh tools/do-compile-ffmpeg.sh $FF_TARGET $FF_TARGET_EXTRA
FF_TARGET 這里是傳進來的armv7a
FF_TARGET_EXTRA 這里沒傳進來桨醋,為空
就是執(zhí)行
sh tools/do-compile-ffmpeg.sh armv7a
又去執(zhí)行當(dāng)前目錄下tools包下的do-compile-ffmpeg.sh 文件,帶個armv7a 參數(shù)進去现斋;(真正的編譯腳本不是comfile-ffmpeg.sh 而是do-compile-ffmpeg.sh 喜最,所有單個文件也可以直接執(zhí)行./tools/do-compile-ffmpeg.sh armv7a ,執(zhí)行的目錄還是在compile-ffmpeg.sh文件所在的目錄)
do-compile-ffmpeg.sh 內(nèi)容的開頭():
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
.
.
設(shè)置各種變量
.
.
#--------------------
echo ""
echo "--------------------"
echo "[*] make NDK standalone toolchain"
echo "--------------------"
. ./tools/do-detect-env.sh
.
.
.
判斷 FF_ARCH 參數(shù)是否空步责,如果為空就輸出 "You must specific an architecture 'arm, armv7a, x86, ...'. 然后退出返顺,
這里的 FF_ARCH 就是傳進來的armv7a(這里講廢話了),有條命令. ./tools/do-detect-env.sh蔓肯;
上面都是廢話,可以不用看振乏,細節(jié)而已蔗包,下面才是重要內(nèi)容
在編譯腳本之前會執(zhí)行do-detect-env.sh 文件檢查運行環(huán)境和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的,執(zhí)行下面的
case "$IJK_NDK_REL" in
10e*)
如果是其他的慧邮,執(zhí)行
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 #檢查對應(yīng)版本的是否存在
這里只檢查了 11*|12*|13*|14*四個版本的耻矮,不妨加上 17試試
11*|12*|13*|14*|17*)
保存之后執(zhí)行 ./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
.
.
.
保存之后執(zhí)行 ./compile-ffmpeg.sh armv7a
2裆装、ERROR: Failed to create toolchain
在執(zhí)行./compile-ffmpeg.sh armv7a 的時候有些系統(tǒng)會保存 Failed to create toolchain
這是因為linux 系統(tǒng)有些使用python版本 是python3(python2的我沒試過)
可以使用rpm 命令檢查python 版本
rpm -qa | grep python
在執(zhí)行do-compile-ffmpeg.sh 中會執(zhí)行 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 報錯
在最后關(guān)鍵時刻,使用NDK 14b編譯 ijkplayer 竟然不行昙沦,就感覺還沒拉出來完琢唾,中間夾斷了那么難受,最后是把NDK 版本改成 17的才可以
四盾饮、編譯多架構(gòu)
比如這里需要編譯 armv7a 與arm64
首先init-android.sh 必須下載對應(yīng)架構(gòu)的源碼
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 文件采桃,F(xiàn)F_ACT_ARCHS_64 只保留armv7a 懒熙、arm64
.
.
.
#FF_ACT_ARCHS_32="armv5 armv7a x86"
#FF_ACT_ARCHS_64="armv5 armv7a arm64 x86 x86_64"
#這里是32位于64位,現(xiàn)在一般的都是64位
FF_ACT_ARCHS_32="armv7a"
FF_ACT_ARCHS_64="armv7a arm64"
FF_ACT_ARCHS_ALL=$FF_ACT_ARCHS_64
.
.
.
執(zhí)行腳本時候使用的就是
./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)
.
.
.
執(zhí)行腳本時候使用的就是
./compile-ijk.sh all