一文让你发现原来FFmpeg这么有意思

前言

其实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真的很牛逼。接下来我会教大家自己怎么实现这个功能。那么来看看做出来的视频如何,某音好像没有这个功能哦,
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

扫描二维码关注公众号,回复: 12202115 查看本文章

如何实现这种效果

这一期,我只是教大家如何通过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,所以只要按照下面的命令执行即可

./build_ffmpeg_andori.sh static

复制代码如果你想编译动态库 只要把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,添加背景音乐,视频画面剪切…有想要了解的也可以在留言中提及。我会做相关方面的调研,

猜你喜欢

转载自blog.csdn.net/lingshengxueyuan/article/details/111874723