同步發表於 http://avenwu.net/ijkplayer/2015/05/07/hands_on_ijkplayer_preparation
談到視頻播放大家都知道ffmpeg,基於其的衍生版本也很多,比如本文的ijkplayer.
試試ijkplayer編譯
去到B站得github主頁,找到ijkplayer項目,clone源碼
git clone git@github.com:Bilibili/ijkplayer.git
根據介紹文檔一步步開始
./init-android.sh
執行初始化的shell腳本,腳本會自動下載ffmpeg的主干代碼
IJK_FFMPEG_UPSTREAM=git://git.videolan.org/ffmpeg.git
IJK_FFMPEG_FORK=https://github.com/Bilibili/FFmpeg.git
IJK_FFMPEG_COMMIT=ijk-r0.2.2-dev
IJK_FFMPEG_LOCAL_REPO=extra/ffmpeg
set -e
TOOLS=tools
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/ffmpeg-$1 ${IJK_FFMPEG_LOCAL_REPO}
cd android/ffmpeg-$1
git checkout ${IJK_FFMPEG_COMMIT}
cd -
}
pull_fork "armv7a"
pull_fork "armv5"
pull_fork "x86"
pull_fork "arm64-v8a"
./init-config.sh
./init-android-libyuv.sh
簡單分析一息腳本做的事情,
首先定義了4個先關的變量,用於后文下載源碼和目錄的文件
1. IJK_FFMPEG_UPSTREAM=git://git.videolan.org/ffmpeg.git
ffmpeg的官方repo地址
2. IJK_FFMPEG_FORK=https://github.com/Bilibili/FFmpeg.git
B站托管與github的ffmpeg分支
3. IJK_FFMPEG_COMMIT=ijk-r0.2.2-dev
可以用來編譯不同平台版本的代碼分支
找到tools目錄的pull-repo-ref.sh腳本,這個腳本用於獲取B站托管的github上的FFmpeg分支,根據不同的目標平台放置不同工作目錄,后面單獨分析;
獲取完代碼后,檢出之前定義的特定分支,也就是ijk-r0.2.2-dev
最后再調用另外兩個腳本init-config.sh和init-android-libyuv.sh
tools/pull-repo-ref.sh
這里腳本接受了三個參數
REMOTE_REPO=https://github.com/Bilibili/FFmpeg.git B站自己托管站github的FFmpeg
LOCAL_WORKSPACE=android/ffmpeg-xxx 本地目標倉庫存放位置,xxx為平台版本
REF_REPO=extra/ffmpeg 遠程ffmpe官方倉庫clone到本地的位置
接下來通過 git clone --reference來獲取B站得FFmpeg,為什么這里的clone加了--reference參數?實際上根據用法介紹,--reference是為了減少從網絡獲取的文件,盡可能從本地的倉庫中獲取;
所以B站FFmpeg應該是基於官方的ffmpeg,這樣的話,由於一開始的時候已經獲取了官方ffmpeg代碼,在獲取B站的分支倉庫時就可以將之前下好的官方倉庫的本地庫作為參考倉庫;
REMOTE_REPO=$1
LOCAL_WORKSPACE=$2
REF_REPO=$3
if [ -z $1 -o -z $2 -o -z $3 ]; then
echo "invalid call pull-repo.sh '$1' '$2' '$3'"
elif [ ! -d $LOCAL_WORKSPACE ]; then
git clone --reference $REF_REPO $REMOTE_REPO $LOCAL_WORKSPACE
cd $LOCAL_WORKSPACE
git repack -a
else
cd $LOCAL_WORKSPACE
git pull --rebase
cd -
fi
./init-config.sh
這個腳本用來安全檢查,如果config/module.sh不存在,那么默認將module-lite.sh拷貝作為module.sh,至於module.sh,在前面已經提到,主要是對標准ffmpeg的剪裁控制
if [ ! -f 'config/module.sh' ]; then
cp config/module-lite.sh config/module.sh
./init-android-libyuv.sh
這個腳本和前面提到的類似,只不過是用來下載依賴包的
IJK_LIBYUV_UPSTREAM=https://github.com/Bilibili/libyuv.git
IJK_LIBYUV_FORK=https://github.com/Bilibili/libyuv.git
IJK_LIBYUV_COMMIT=ijk-r0.2.1-dev
IJK_LIBYUV_LOCAL_REPO=extra/libyuv
set -e
TOOLS=tools
echo "== pull libyuv base =="
sh $TOOLS/pull-repo-base.sh $IJK_LIBYUV_UPSTREAM $IJK_LIBYUV_LOCAL_REPO
echo "== pull libyuv fork =="
sh $TOOLS/pull-repo-ref.sh $IJK_LIBYUV_FORK ijkmedia/ijkyuv ${IJK_LIBYUV_LOCAL_REPO}
cd ijkmedia/ijkyuv
git checkout ${IJK_LIBYUV_COMMIT}
cd -
開始編譯
初始化完畢后就可以依次執行下面的腳本開始編譯了
cd android
./compile-ffmpeg.sh clean
./compile-ffmpeg.sh
./compile-ijk.sh
這里可能會遇到一些問題,根據自身環境不同不一定一樣;筆者在編譯時,第一次直接在master上編,結果提示有一個.h找不到,根據文檔指南切回k0.2.3后重新來就OK了,雖然上面也說了可以在maste直接編,但實際上是不行的;
最后編譯成功的話會看到幾個so的輸出
注意默認情況下這里之變異了armv7的幾個so庫,其他平台的需要跟上參數編譯
compile-ijk.sh armv5|armv7a|x86|arm64-v8a
或者
compile-ijk.sh all
但是,事情不是這么簡單,但加上all之后,armv7仍然成功,但是x86編譯就跪了
同時armv5也跪了,原因都是找不libijkffmpeg.so
沖armv7得輸出日志可以看到,這個文件是build下從各自版本的編譯文件拷貝而來;
定位到build文件夾,里面只有armv7的相關文件,所以根本拷貝就不會成功,自然就掛了;
aven-mac-pro:android aven$ ./compile-ijk.sh all
Android NDK: ERROR:/Users/aven/work/video/ijkplayer/android/ijkmediaplayer-armv5/jni/ffmpeg/Android.mk:ijkffmpeg: LOCAL_SRC_FILES points to a missing file
Android NDK: Check that /libijkffmpeg.so exists or that its path is correct
/Users/aven/Android/android-ndk-r10c/build/core/prebuilt-library.mk:45: *** Android NDK: Aborting . Stop.
/Users/aven/work/video/ijkplayer/android
[armeabi-v7a] Prebuilt : libijkffmpeg.so <= /Users/aven/work/video/ijkplayer/android/build/ffmpeg-armv7a/output/
[armeabi-v7a] Install : libijkffmpeg.so => libs/armeabi-v7a/libijkffmpeg.so
[armeabi-v7a] Compile thumb : ijkplayer <= ff_cmdutils.c
[armeabi-v7a] Compile thumb : ijkplayer <= ff_ffplay.c
[armeabi-v7a] Compile thumb : ijkplayer <= ijkmeta.c
[armeabi-v7a] Compile thumb : ijkplayer <= ijkplayer.c
[armeabi-v7a] Compile thumb : ijkplayer <= ffpipeline_ffplay.c
[armeabi-v7a] Compile thumb : ijkplayer <= ffpipenode_ffplay_vdec.c
[armeabi-v7a] Compile thumb : ijkplayer <= ffpipenode_ffplay_vout.c
[armeabi-v7a] Compile thumb : ijkplayer <= ffmpeg_api_jni.c
[armeabi-v7a] Compile thumb : ijkplayer <= ijkplayer_android.c
[armeabi-v7a] Compile thumb : ijkplayer <= ijkplayer_jni.c
[armeabi-v7a] Compile thumb : ijkplayer <= ffpipeline_android.c
[armeabi-v7a] Compile thumb : ijkplayer <= ffpipenode_android_mediacodec_vdec.c
[armeabi-v7a] Compile thumb : ijkplayer <= ffpipenode_android_mediacodec_vout.c
[armeabi-v7a] Compile thumb : ijksdl <= ijksdl_vout_overlay_ffmpeg.c
[armeabi-v7a] Compile thumb : ijksdl <= image_convert.c
[armeabi-v7a] Compile thumb : ijksdl <= android_nativewindow.c
[armeabi-v7a] Compile thumb : ijksdl <= ijksdl_vout_android_nativewindow.c
[armeabi-v7a] SharedLibrary : libijksdl.so
[armeabi-v7a] SharedLibrary : libijkplayer.so
[armeabi-v7a] Install : libijkplayer.so => libs/armeabi-v7a/libijkplayer.so
[armeabi-v7a] Install : libijksdl.so => libs/armeabi-v7a/libijksdl.so
[armeabi-v7a] Install : libijkutil.so => libs/armeabi-v7a/libijkutil.so
/Users/aven/work/video/ijkplayer/android
Android NDK: ERROR:/Users/aven/work/video/ijkplayer/android/ijkmediaplayer-x86/jni/ffmpeg/Android.mk:ijkffmpeg: LOCAL_SRC_FILES points to a missing file
Android NDK: Check that /libijkffmpeg.so exists or that its path is correct
/Users/aven/Android/android-ndk-r10c/build/core/prebuilt-library.mk:45: *** Android NDK: Aborting . Stop.
/Users/aven/work/video/ijkplayer/android到libijkffmpeg.so
這個時候只能一步一步回溯,首先查看compile-ffmpeg.sh
UNI_BUILD_ROOT=`pwd`
FF_TARGET=$1
set -e
set +x
FF_ALL_ARCHS="armv5 armv7a x86 arm64-v8a"
FF_ACT_ARCHS="armv5 armv7a x86"
echo_archs() {
echo "===================="
echo "[*] check archs"
echo "===================="
echo "FF_ALL_ARCHS = $FF_ALL_ARCHS"
echo "FF_ACT_ARCHS = $FF_ACT_ARCHS"
echo ""
}
case "$FF_TARGET" in
"")
echo_archs
sh tools/do-compile-ffmpeg.sh armv7a
;;
armv5|armv7a|x86|arm64-v8a)
echo_archs
sh tools/do-compile-ffmpeg.sh $FF_TARGET
;;
all)
echo_archs
for ARCH in $FF_ACT_ARCHS
do
sh tools/do-compile-ffmpeg.sh $ARCH
done
;;
clean)
echo_archs
for ARCH in $FF_ALL_ARCHS
do
cd ffmpeg-$ARCH && git clean -xdf && cd -
done
rm -rf ./build/ffmpeg-*
;;
check)
echo_archs
;;
*)
echo "Usage:"
echo " compile-ffmpeg.sh armv5|armv7a|x86|arm64-v8a"
echo " compile-ffmpeg.sh all"
echo " compile-ffmpeg.sh clean"
echo " compile-ffmpeg.sh check"
exit 1
;;
esac
echo "\n--------------------"
echo "[*] Finished"
echo "--------------------"
echo "# to continue to build ijkplayer, run script below,"
echo "sh compile-ijk.sh "
眼尖的話應該看到了,這里也是需要跟參數來決定編譯的版本,問題引刃而解。
再次編譯成功.