Shell 脚本 - 自己动手编译 FFmpeg

2,342 阅读2分钟

有了 Makefile、CMake 和 Shell 的基础后,我们就可以自己动手编译 FFmpeg 了。当然网上能找到别人已经有编译好的库文件,我们之所以折腾这么一大圈,还是为了自己以后能去裁剪编译。之前在公司看老大一顿 shell 命令操作,觉得非常的高大上,觉得自己很菜,觉得应该要很多年才能达到这程度吧。自己用心学了才知道,其实也就一周的时间完完全全足够了。

我们先来做一些准备工作,准备一台 Linux 云主机或者一台 Mac 电脑,下载 ndk ,下载 FFmpeg

Linux 环境(Ubuntu 14.04 ,x86_64)
NDK 版本(android-ndk-r16b)
FFmpeg 版本(ffmpeg-3.3.9)

关于版本的选择问题,我在国内看了一圈,大家基本都是用的 2.x.x 的版本。高版本与低版本相比,一般性能和各个方面都会有一些改进,那我们就用高版本?其实也不完全是这样,很多低版本的 api 会被废弃掉,比如视频解码方法 avcodec_decode_video2 在 3.x.x 的版本后取而代之的是 avcodec_send_packet 和 avcodec_receive_frame 。因此如果你想去查一下 3.x.x 版本的 api 资料可能会发现比较少,或者开发过程中遇到某些问题也会比较棘手。因此建议大家学习时尽量使用较高的版本,开发时尽量使用大众的版本。

下载完成后把下载好的 ndk 和 FFmpeg 用 xftp 推到 linux 云主机上。把 ndk 解压到 /lib/ndk 目录下,然后配置 NDK_PATH 环境变量:

# 配置NDK路径
export NDK_PATH=/lib/ndk/android-ndk-r16b
export PATH=$NDK_PATH:$PATH

FFmpeg 直接解压到工作目录下:

ubuntu@VM-0-9-ubuntu:~/ffmpeg-3.3.9$ ls
arch.mak                CREDITS                ffserver.c         LICENSE.md
Changelog               doc                    ffserver_config.c  MAINTAINERS
cmdutils.c              ffmpeg.c               ffserver_config.h  Makefile
cmdutils_common_opts.h  ffmpeg_cuvid.c         INSTALL.md         presets
cmdutils.h              ffmpeg_dxva2.c         libavcodec         README.md
cmdutils_opencl.c       ffmpeg_filter.c        libavdevice        RELEASE
common.mak              ffmpeg.h               libavfilter        RELEASE_NOTES
compat                  ffmpeg_opt.c           libavformat        tests
configure               ffmpeg_qsv.c           libavresample      tools
CONTRIBUTING.md         ffmpeg_vaapi.c         libavutil          VERSION
COPYING.GPLv2           ffmpeg_vdpau.c         libpostproc        version.sh
COPYING.GPLv3           ffmpeg_videotoolbox.c  library.mak
COPYING.LGPLv2.1        ffplay.c               libswresample
COPYING.LGPLv3          ffprobe.c              libswscale

我们发现目录下已经有写好的 Makefile 编译文件了,那是不是可以直接编译运行呢?使用 make 命令出现如下错误:

Makefile:2: config.mak: No such file or directory
Makefile:67: /common.mak: No such file or directory
Makefile:114: /libavutil/Makefile: No such file or directory
Makefile:114: /library.mak: No such file or directory
Makefile:116: /doc/Makefile: No such file or directory
Makefile:206: /tests/Makefile: No such file or directory
make: *** No rule to make target '/tests/Makefile'.  Stop.

这些文件怎么来?在 configure 脚本文件里面,当然刚开始大家基本看不懂,这也是为什么我们要先学学 shell 脚本基础的原因。我们只需要再写一个 build.sh 脚本来执行 ./configure 脚本文件即可,至于需要传递哪些参数,怎么裁剪 so 动态库这里先不详细讲,大家可以用 ./configure --help 来查看,学到后面我们自然而然就该知道怎么裁剪了,刚开始就能很明白一般不太现实。当然我们也可以去 copy 了别人写好的脚本文件,但有时脚本的一个空格不对,都有可能浪费我们一周的时间。因此我还是建议大家要能自己写,以后我们可能会遇到各式各样的第三方库,而编译 FFmpeg 库文件是我所遇到的非常简单的一个。

#!/bin/bash
. /etc/profile
function build
{
    echo "start build ffmpeg for $ARCH"
    ./configure --target-os=linux \
    --prefix=$PREFIX --arch=$ARCH \
    --disable-doc \
    --enable-shared \
    --disable-static \
    --disable-yasm \
    --disable-asm \
    --disable-symver \
    --enable-gpl \
    --disable-ffmpeg \
    --disable-ffplay \
    --disable-ffprobe \
    --disable-ffserver \
    --cross-prefix=$CROSS_COMPILE \
    --enable-cross-compile \
    --sysroot=$SYSROOT \
    --enable-small \
    --extra-cflags="-Os -fpic $ADDI_CFLAGS" \
    --extra-ldflags="$ADDI_LDFLAGS" \
    $ADDITIONAL_CONFIGURE_FLAG
    make clean
    make
    make install
    echo "build ffmpeg for $ARCH finished"
}

ARCH=arm
CPU=arm
PREFIX=$(pwd)/android/$ARCH
TOOLCHAIN=$NDK_PATH/android-toolchains/arm-19
CROSS_COMPILE=$TOOLCHAIN/bin/arm-linux-androideabi-
ADDI_CFLAGS="-marm"
SYSROOT=$TOOLCHAIN/sysroot
build
ubuntu@VM-0-9-ubuntu:~/ffmpeg-3.3.9/android/arm/lib$ ls
libavcodec.so            libavformat.so            libswresample.so
libavcodec.so.57         libavformat.so.57         libswresample.so.2
libavcodec.so.57.89.100  libavformat.so.57.71.100  libswresample.so.2.7.100
libavdevice.so           libavutil.so              libswscale.so
libavdevice.so.57        libavutil.so.55           libswscale.so.4
libavdevice.so.57.6.100  libavutil.so.55.58.100    libswscale.so.4.6.100
libavfilter.so           libpostproc.so            pkgconfig
libavfilter.so.6         libpostproc.so.54
libavfilter.so.6.82.100  libpostproc.so.54.5.100

如果大家不出意外会得到以上文件,我们发现编译出来是 linux 的命名方式,因此我们需要在 configure 中改一下生成文件名的格式:

# SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'
# LIB_INSTALL_EXTRA_CMD='?(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
# SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
# SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR) $(SLIBNAME)'
# 替换成如下
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='?(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'

最后我们把生成好的 .so 和头文件 copy 整合到 Android 工程下,就可以开始做视频的开发了,至于怎么整合到 AS ,可以参考 《CMake 语法 - 详解 CMakeLists.txt》 一文。关于视音频编解码,视音频同步播放,直播推拉流等等,会在接下来的文章中,给大家陆陆续续的介绍。 视频链接:pan.baidu.com/s/17CiYcqTj… 视频密码:hq2d