原来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,添加背景音乐,视频画面剪切...有想要了解的也能够在留言中说起。我会作相关方面的调研,

相关文章
相关标签/搜索