前言
其實FFmpeg大家都耳熟能詳的的一個東西了,知名的ijkplayer 就是有Bilibili開源出來的播放器也是基于FFmpeg做出來的。但是FFmpeg不僅僅止于音視訊的播放裁剪功能,還能幹些更有趣的事情,就比如說視訊的畫面拼接,對于一個Android開發者來說,一想到FFmpeg c/c++是跑不掉的。下載下傳官方庫,然後編譯成不同平台的so,然後在通過jni內建到項目中,這一個開頭就難倒了不少開發者。一個問題是如何編譯出這個so。如何把編譯好的檔案內建到項目中。這個我之後的文章會詳細說明,這裡我隻和大家說說有趣在哪裡。
說道這裡 我不得不說,現在各個大廠都在做統一前端的開發語言和架構,搞得開發者TMD頭都大,其實不還是做得都是一些UI頁面而已,通過不同的方式渲染而已,如果真的要做一些定制化的功能,還是離開不了原生。
開始之前已經給大家準備好了安裝環境和各種視訊資料帶你入門FFmpeg,資料放在自己的群裡面:832218493(需要自取)
Android FFmpeg視訊畫面拼接
通過标題大家可能還是不太明白啥意思,我就上幾張我做的這個App的截圖吧,順便放幾張動态圖,可能大家能知道個大概功能。其實大家看了之後,可能感覺感覺市面上已經有做到了這種效果的App了,但是作為一個Android攻城獅,必須要知道他是怎麼做出來的,在ios上做這種效果很容易,有原生的Api提供,但是苦逼的Android 那隻能通過C/C++來實作,原生搞的話很難。
這個App大概有以下功能(目前并未開源,項目位址)
視訊畫面拼接(主要的)
視訊寬高裁剪
視訊時長裁剪
添加視訊邊框及修改邊框顔色
添加視訊封面
添加視訊背景圖檔
添加視訊水印
添加背景音樂
下面是App做出來的兩個視訊轉gif的圖檔
這個app已有下面的頁面,不過現在還沒有開源,還有很多地方要改。功能是實作了。但是頁面還有很多優化的地方,是以啊 FFmpeg真的很牛逼。接下來我會教大家自己怎麼實作這個功能。那麼來看看做出來的視訊如何,某音好像沒有這個功能哦,
如何實作這種效果
這一期,我隻是教大家如何通過shell 指令實作一個視訊畫面拼接。首先從最基礎的功能來實作吧。然後在根據目前的功能進行擴充。至于FFmpeg庫的編譯,一時半會兒也說不完。參數配置也很麻煩,尤其是不同的平台坑很多。這裡我就以最簡單的方式交大家如何實作吧
第一步
既然要做功能,第一步當然是找相應的工具了,我們可以通過FFmpeg官網找到,對應自己平台的靜态庫,大家别下錯了哈,static binary不要下載下傳錯了,下載下傳成源檔案了。因為官方已經給我們編譯好了靜态庫,可以直接通過shell 腳本就可以簡單的走起來。
FFmpeg官方網站庫
打開連結,我這邊選中的是mac os 可以看到底下提供了 static 庫。我們可以直接下載下傳下來就行了。Ubuntu 和windows 都是一樣的 都有現成的庫。可以下載下傳下來。
下載下傳下來就是一個這個東西。我這邊大概71M。還挺大的,因為裡面官方給我們把大部分基本的功能都給編譯進去了。是以這麼大,但是如果我們自己編譯的話,會小很多。可以吧一下不需要的東西直接disable
第二步
那當然是打開我們的terminal,windows 直接win+R 然後cmd就ok,然後cd 到我們下載下傳的ffmpeg靜态庫的檔案路徑,執行一下指令,不出意外的話,這時候你應該可以看到以下頁面
./ffmpeg
複制代碼如果出現一下内容,說明這時候你的ffmpeg 已經ok了
如果說權限不足的話 ,cd到你的靜态庫路徑下執行這個就可以了。加個sudo,然後在change mode 一下 賦予777權限
chmod +x ffmpeg
chmod 777 ffmpeg
複制代碼這時候ffmpeg環境已經準備好了。接下來萬事俱備隻欠東風了。
第三步
視訊拼接,那麼如何視訊拼接呢,不用擔心 ffmpeg 已經給我們做好了相應的封裝了。隻要了解相應的指令就可以完成了最基礎的視訊拼接功能了。其實ffmpeg不僅僅如此啊,他的功能太強大了。
先簡單的來幾個指令看看,檢視視訊檔案資訊
./ffmpeg -i input.mp4
複制代碼這時候我們可以看到視訊的具體資訊fps,寬高啊,視訊品質啊,等等很多資訊
-i 的指令就是入參的,接下來我們直接看如何通過指令把一個視訊合在一起,就比如上面兩個視訊合在一起的小姐姐,我們通過電腦簡單的來合成一下。
./ffmpeg -i input2.mp4 -i input2.mp4 -filter_complex [0][1]vstack -y output.mp4
複制代碼成功的話應該是以下頁面
這一個MP4檔案是同級目錄下的檔案,大家可以換成自己的檔案名就可以,至于filter_complex嗎?我這邊就大白話講了,就相當于我們java 中的函數一樣,你把輸入給他 在這個方法體内,把相應的輸出給你。
vstack 可以官網看到這樣的介紹 Stack input videos vertically.就是垂直拼接視訊的意思,同理如何想水準的話,隻要把vstack 改成hstack就可以了,老鐵們是不是很簡單,很給力,
最主要的是自己通過指令行就可以完成一些視訊的基本操作,什麼ps,Photoshop,我指令行就ok了。哈哈哈哈哈哈哈哈
剛剛作出來的視訊效果,截圖給大家看看
編譯Android平台FFmpeg
關于編譯Android 平台的庫可能網上有一大堆,反正一搜尋,肯定有你需要的,這邊我主要教大家使用靜态庫而非動态庫,這樣你會省了很多很多的麻煩,各種so庫的來回粘貼複制,還要寫cmakelist文集,配置gradle,對于沒怎麼玩過FFmpeg的人來說可能需要搞很長時間,這裡我将帶給大家另一種玩法
動态庫
動态庫其實就是編譯出來的so庫,link到我們的項目中然後load library 然後通過jni的方式進行操作c上面的東西,這邊就是簡單概括一下,那我知道了需要哪些東西了,那我們接下來就是,編譯這個so庫,大家可以在網上看到FFmpeg編譯出來的有很多so 你要一個一個的把他們放進我們的項目中。然後cmakelist裡面添加東西。這裡我教大家把這幾個庫編譯到一個so裡面,可以省了你很多麻煩
以上準備都ok的話,這邊就可以執行腳本指令了打開我們下載下傳的FFmpeg壓縮包,可以看到這些目錄結構,我們編譯主要用到的就是configure這個binary。可以在下圖中看到
腳本我這邊就把一部分代碼貼上去,全部的我放在了github上了(下面這個腳本名稱叫做build_ffmpeg_android.sh,可以在我上面的寫的位址裡找到),我會寫一些注釋在上面
可以看到下面的 代碼中有一個MODULE(主要做一些裡面庫的enabel 和disable,把需要的庫我們編譯進去 不需要的當然是不用了)
GENERAL(主要作用是一些參數的設定和額外的庫添加)和LIB_TYPE(這個就是設定編譯shared還是static的了)靜态庫或者動态庫
function build
{
pushd ffmpeg
./configure \
--logfile=config.log \
--target-os=android \
--prefix=$PREFIX \
${MODULE} \
${GENERAL} \
${LIB_TYPE} \
--sysroot=$PLATFORM \
--extra-cflags="-fPIE -fPIC -std=c11" \
--extra-ldflags="$flags $shared_flag" \
# essencial for dynamic library
sed -i -E "s/^(#define HAVE_SYSCTL).*/\1 0/" config.h
make clean
make -j$NUM_OF_CORE
make install
popd
}
build
這個就是GENERAL的參數
GENERAL=" \
--extra-libs="-lgcc" \
--arch=${ARCH} \
--cc=$PREBUILT/bin/${BIN_PREFIX}-gcc \
--cross-prefix=$PREBUILT/bin/${BIN_PREFIX}- \
--nm=$PREBUILT/bin/${BIN_PREFIX}-nm \
--extra-cflags="-I$X264_INCLUDE" \
--extra-ldflags="-L$X264_LIB" \
"
這個是module的參數 隻放了一部分,用到的可以enable 用不到的disable 不然編譯出來的庫很大。那我們的apk也會相應的很大,可以到github下載下傳原始檔案
MODULE=" \
--enable-jni \
--enable-pic \
--enable-gpl \
--enable-zlib \
--enable-yasm \
--enable-small \
--enable-pthreads \
--enable-mediacodec \
--enable-libx264 \
--enable-cross-compile \
--disable-doc \
--disable-ffplay \
--disable-ffprobe \
--disable-network \
--enable-neon
--disable-linux-perf \
--enable-encoder=libx264 \
--enable-encoder=aac \
--enable-encoder=mpeg4 \
--enable-encoder=mjpeg \
--enable-encoder=png \
--disable-muxers \
靜态庫
這邊腳本裡寫了一些判斷,我們可以執行腳本的時候 再加個字段就可以編譯出我們需要的靜态庫,我這邊的腳本名字叫做build_ffmpeg_android.sh,是以隻要按照下面的指令執行即可
複制代碼如果你想編譯動态庫 隻要把static 改成shared即可。
現在的電腦應該編譯的很快,執行成功應該可以看到下面的目錄,so已經編譯出來了
靜态庫已經出來了
把編譯出來的庫合成一個so庫
隻要把以下的代碼添加到編譯腳本裡面即可。
$TOOLCHAIN/bin/${BIN_PREFIX}-ld \
-rpath-link=$PLATFORM/usr/lib \
-L$PLATFORM/usr/lib \
-L$PREFIX/lib \
-L$X264_LIB \
-soname libffmpeg.so -shared -nostdlib -Bsymbolic --whole-archive --no-undefined -o \
$PREFIX/libffmpeg.so \
$PREFIX/lib/libavcodec.a \
$PREFIX/lib/libavfilter.a \
$PREFIX/lib/libavformat.a \
$PREFIX/lib/libavutil.a \
$PREFIX/lib/libswresample.a \
$PREFIX/lib/libswscale.a \
$X264_ALIB/libx264.a \
-lc -lm -lz -ldl -llog --dynamic-linker=/system/bin/linker \
$TOOLCHAIN/lib/gcc/${BIN_PREFIX}/4.9.x/libgcc.a
從上面腳本可以看到 相當于把這些庫linker到我們上面的libffmpeg.so裡面。
成功的話可以看到ffmpeg 目錄下的Android中看到這個so庫
可以看到libffmpeg.so已經出來了
編譯Lib264庫
作用
為什麼用這個庫呢,如果說你已經以上步驟都成功了,而且已經運作到Android機上面了,你會發現編碼出來的視訊檔案明顯品質很差,不應該說很差,反正肯定是自己不滿意的結果。說了這麼多,大家應該知道這個庫的作用了,提高編碼品質,為什麼我在官網下載下傳的pc庫會品質很好呢,那是因為他們已經把這個庫編進去了而且已經enable。那麼我們這裡要做的就是去下載下傳Lib264官方源碼,編譯出Android平台的 然後把這個庫給打進FFmpeg裡面。
編譯Lib264
這個庫編譯就比較簡單了。參數和代碼沒有那麼多,github上面放的腳本名字叫做(build_x264_andorid.sh)大家下載下傳下來就可以用的
如果想編譯不同的版本同樣可以通過 字尾shared 或者static 就可以了
LIB_TYPE=${1-static}
echo '@@@#####'${LIB_TYPE}
function build
{
pushd x264
# remove suffix of libx264.so
sed -in 's/so\.\$API/so/g' configure
./configure \
--prefix=./android/$ABI \
--enable-$LIB_TYPE \
--enable-pic \
--host=$BIN_PREFIX \
--cross-prefix=${PREBUILT}/bin/${BIN_PREFIX}- \
--extra-cflags="-fPIC -fPIE -std=c11" \
--sysroot=$PLATFORM
sed -i 's/-f -s/-f/g' ./Makefile
make clean
make -j$NUM_OF_CORE
make install
tree android
popd
}
build
printf "$success" "x264"
./build_x264_android.sh shared
執行成功應該可以看到下面的目錄在x264/android/目錄下,so已經編譯出來了
FFmpeg Lib264合成
上面已經把每個平台的庫都編譯好了,那我們怎麼把這兩個庫合成在一起呢,細心的同學已經看到了,我上面貼腳本的時候已經把代碼貼進去了,就是在我們編譯腳本build_ffmpeg_android.sh的時候已經帶進去了就是那個GENERAL字段
看看下面的字段cflags 和 ldflags 已經把我們之前編譯的x264編譯進去了。
X264_INCLUDE=../x264/android/$ABI/include
X264_LIB=../x264/android/$ABI/lib
X264_ALIB=../x264
GENERAL=" \
--extra-libs="-lgcc" \
--arch=${ARCH} \
--cc=$PREBUILT/bin/${BIN_PREFIX}-gcc \
--cross-prefix=$PREBUILT/bin/${BIN_PREFIX}- \
--nm=$PREBUILT/bin/${BIN_PREFIX}-nm \
--extra-cflags="-I$X264_INCLUDE" \
--extra-ldflags="-L$X264_LIB" \
"
編譯不同ARCH庫(armeabi-v7a arm64-v8a…)
這個就比較簡單了,既然一個平台已經成功,那麼其他的改一下
編譯平台不就行了。可以在我們的腳本中修改一些參數即可,
我這邊做了一些判斷可以在編譯腳本前,在我們的common.sh目錄下修改以下ARCH既可以,然後在執行build_ffmpeg_android.sh即可。
#ARCH=arm
ARCH=aarch64
[[ $ARCH = "arm" ]] && \
{ BIN_PREFIX=arm-linux-androideabi; ABI=armeabi-v7a; } || { BIN_PREFIX=aarch64-linux-android; ABI=arm64-v8a; }
NDK=~/Downloads/android-ndk-r14b
PLATFORM=$NDK/platforms/android-21/arch-arm64
PREBUILT=$NDK/toolchains/${BIN_PREFIX}-4.9/prebuilt/linux-x86_64
TOOLCHAIN=$NDK/toolchains/${BIN_PREFIX}-4.9/prebuilt/linux-x86_64
NUM_OF_CORE=$(nproc)
success="${BLACKB}${YELLOWF}build %s success${RESET}\n"
以上就是common.sh腳本。隻要修改上面的arch參數就行 ,如果要變異arm的話記得把PLATFORM這個參數後面的64去了。
收尾
可能上面有說的不清楚的。大家可以在留言中或者私信中 提問。如果上面有說錯的地方,大家可以積極的和我說。我會在文章中糾正。
To be continue… 下回我會帶給大家 關于App的一些内容。比如畫面拼接,添加logo,添加背景音樂,視訊畫面剪切…有想要了解的也可以在留言中提及。我會做相關方面的調研,