原來FFmpeg這麼有意思 (二)

前提

文章耽擱了兩星期了,可能很多老鐵已經忘了,上一篇文章的內容了,不妨回顧一下,以前的文章裏面就簡單的說起了FFmpeg的一些簡單命令的用法,官方下載不一樣平臺的靜態庫,能夠直接執行binary 文件來編輯一些音視頻文件。我上次只是說了視頻畫面合成的用法,經過vstack和hstack,來進行合成。此次呢 我將教你們,如何在本身的Android手機上進行視頻畫面拼接的方法 以及如何經過官方庫編譯出Android平臺的so庫及靜態庫。此次內容可能會不少,也涉及到了不少shell腳本語言的的東西。但願老鐵們耐心看看,絕對會有幫助。html

這個是以前的系列java

原來FFmpeg這麼有意思 (一)linux

這裏教你們一些騷操做,android

  • 根本不須要經過JNI的方式來執行FFmpeg的方法,直接java語言就能夠來玩FFmpeg,可是有些功能是有侷限性的。(靜態庫)
  • 把編譯出的全部so庫打包成一個so來玩,省事。(動態庫)

準備

這邊主要是爲了你們下載版本號相同,根據腳本能夠編譯成功,否則每一個版本里面可能要修改一些參數 我這裏就按照個人環境和你們說一下把git

  • ubuntu ( Ubuntu 18.10 )github

  • FFmpeg 官方庫(4.0.2) x264 官方庫(最新就行)shell

  • 這邊已經上傳到了github(編譯腳本及編譯庫,腳本通用,可是不一樣平臺庫可能不一樣)ubuntu

FFmpeg 官方bash

x264 官方app

github下載地址

預熱

我會把編譯好的FFmpeg靜態庫傳到github,你們能夠直接拿來用。 github下載地址

App執行靜態庫腳本

在咱們的app中若是說想執行二進制文件,必須放在咱們的私有目錄下,sdcard只是Android文件系統linker出來的一個文件夾,是沒有權限執行二進制文件的,而咱們App的私有目錄是能夠的。下面我會給出一下代碼 僅供你們參考。

二進制的FFmpeg已經上傳到了github ,若是有興趣的同窗能夠下載下來,本身的App中跑起來,咱們能夠把這個文件放在assets文件夾下,而後App運行的時候把這個文件copy到App的私有目錄下

boolean isFileCopied = FileUtils.copyBinaryFromAssetsToData(App.getInstance(),
                        cpuArchNameFromAssets + File.separator + FileUtils.ffmpegFileName,
                        FileUtils.ffmpegFileName);

                // make file executable
                if (isFileCopied) {
                    if (!ffmpegFile.canExecute()) {
                        Log.d(BuildInfo.TAG, "FFmpeg is not executable, trying to make it executable ...");
                        if (ffmpegFile.setExecutable(true)) {
                            Log.d(BuildInfo.TAG, "FFmpeg is executable");
                        }
                    } else {
                        Log.d(BuildInfo.TAG, "FFmpeg is executable");
                    }
                }

複製代碼

上面的代碼本身能夠編寫。我這就不所有貼了。App運行起來後,把這個文件copy到本地,而後調用

ffmpegFile.setExecutable(true)

複製代碼

這樣就能夠執行FFmpeg 了。Android中也提供了執行commend的方法

public static Process run(String[] commandString) {
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(commandString);
            String output = Util.convertInputStreamToString(process.getErrorStream());
            Log.i("cuieney",output);
        } catch (IOException e) {
            Log.e(BuildInfo.TAG,"Exception while trying to run: " + commandString+e.toString());
        }
        return process;
    }
    

複製代碼

就是經過調用runtime.exec就能夠了 把命令寫進去就好。

run({"ffmpeg",""})

複製代碼

這樣就ok了。成功的話能夠在logcat 中看到這些,log太多了 我就沒複製

ffmpeg version 4.0.2 Copyright (c) 2000-2018 the FFmpeg developersbuilt with gcc 4.9.x (GCC) 20150123 (prerelease)........

複製代碼

我這裏根據編譯出來的庫,完成了一些功能

apk下載地址

掃二維碼也是能夠下載的

downloadapk.png

接下來就是正題了。編譯這個東西。

編譯Android平臺FFmpeg

關於編譯Android 平臺的庫可能網上有一大堆,反正一搜索,確定有你須要的,這邊我主要教你們使用靜態庫而非動態庫,這樣你會省了不少不少的麻煩,各類so庫的來回粘貼複製,還要寫cmakelist文集,配置gradle,對於沒怎麼玩過FFmpeg的人來講可能須要搞很長時間,這裏我將帶給你們另外一種玩法

動態庫

動態庫其實就是編譯出來的so庫,link到咱們的項目中而後load library 而後經過jni的方式進行操做c上面的東西,這邊就是簡單歸納一下,那我知道了須要哪些東西了,那咱們接下來就是,編譯這個so庫,你們能夠在網上看到FFmpeg編譯出來的有不少so 你要一個一個的把他們放進咱們的項目中。而後cmakelist裏面添加東西。這裏我教你們把這幾個庫編譯到一個so裏面,能夠省了你不少麻煩

  • 以上準備都ok的話,這邊就能夠執行腳本命令了打開咱們下載的FFmpeg壓縮包,能夠看到這些目錄結構,咱們編譯主要用到的就是configure這個binary。能夠在下圖中看到

image.png

腳本我這邊就把一部分代碼貼上去,所有的我放在了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,因此只要按照下面的命令執行便可

./build_ffmpeg_andori.sh static
複製代碼

若是你想編譯動態庫 只要把static 改爲shared便可。

如今的電腦應該編譯的很快,執行成功應該能夠看到下面的目錄,so已經編譯出來了

image.png

靜態庫已經出來了

把編譯出來的庫合成一個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庫

image.png

能夠看到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已經編譯出來了

image.png

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,添加背景音樂,視頻畫面剪切...有想要了解的也能夠在留言中說起。我會作相關方面的調研,

相關文章
相關標籤/搜索