前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >音视频平凡之路之FFmpeg编译全过程

音视频平凡之路之FFmpeg编译全过程

作者头像
马上就说
发布2020-11-11 17:32:16
4.8K0
发布2020-11-11 17:32:16
举报
文章被收录于专栏:码上就说码上就说

FFmpeg是音视频领域绕不过去的开源库,编译FFmpeg是音视频开发的基本功,FFmpeg就像一个音视频开源框架,很多的开源库都像插件一样作为FFmpeg的子模块,例如openssl、x264、x265、fdk-aac等等库都可以通过插件的形式编译进FFmpeg开源项目中。本文主要的目的是介绍一下FFmpeg的编译过程,以及如何将这些插件编译进FFmpeg中。

1.编译FFmpeg

首先要下载一下FFmpeg库文件:

代码语言:javascript
复制
git clone https://github.com/FFmpeg/FFmpeg

然后切换到n4.0.3 tag 分支,这个分支我试过,交叉编译是没有问题的。

编译工具:android-ndk-r14b

FFmpeg有很多配置选项,你可以直接使用./configure --help查看一下,后续你在编译的时候通过在这里面查找一下编译参数。

一般情况下编译FFmpeg,还需要更改一些参数,让编译出来的库文件按照正常的命名,并且没有额外的链接。

FFmpeg项目中configure中修改一些参数;

代码语言:javascript
复制
SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)

改为:

代码语言:javascript
复制
SLIBNAME_WITH_MAJOR='$(SLIBNAME)-$(LIBMAJOR)$(SLIBSUF)'
代码语言:javascript
复制
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR) $(SLIBNAME)'

改为

代码语言:javascript
复制
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'

单独编译FFmpeg项目,下面就是编译的脚本:

代码语言:javascript
复制
#!/bin/bash
export NDK_ROOT=/Users/jeffmony/tools/android-ndk-r14b # 修改自己本地的ndk路径

build() {
    API=24
    ARCH=$1
    PLATFORM=$2
    SYSROOT=$NDK_ROOT/platforms/android-$API/arch-$ARCH/
    CROSS_PREFIX=$NDK_ROOT/toolchains/$PLATFORM-4.9/prebuilt/darwin-x86_64/bin/$PLATFORM-
    PREFIX=$(pwd)/android/$ARCH #自己指定一个输出目录
    rm -rf $(pwd)/android/$ARCH

    echo "开始编译ffmpeg $ARCH so"

    ./configure \
    --prefix=$PREFIX \
    --disable-doc \
    --disable-shared \
    --enable-static \
    --disable-x86asm \
    --disable-asm \
    --disable-symver \
    --enable-gpl \
    --disable-ffmpeg \
    --disable-ffplay \
    --disable-ffprobe \
    --enable-small \
    --enable-cross-compile \
    --cross-prefix=$CROSS_PREFIX \
    --target-os=android \
    --arch=$ARCH \
    --sysroot=$SYSROOT
}

# build armv7a
build arm arm-linux-androideabi
make clean
make -j8
make install

echo "完成ffmpeg $ARCH 编译..."


# build armv8a
build arm64 aarch64-linux-android
make clean
make -j8
make install

echo "完成ffmpeg $ARCH 编译..."

设置自己的交叉工具链,选择编译到项目中的android文件夹下,编译成功之后,会在android文件夹下生成arm和arm64两个文件夹。

每个文件夹的文件包括 include lib share,include是头文件,lib下面是编译的库文件,静态库就是.a文件,动态库就是.so文件,share文件夹下面是一些FFmpeg的example。

很想把这些库合成一个动态库,这样既能压缩文件,使用的时候有非常方便。好在ndk中提供了strip工具可以压缩库文件。

代码语言:javascript
复制
#!/bin/bash
export NDK_ROOT=/Users/jeffmony/tools/android-ndk-r14b # 修改自己本地的ndk路径

build() {
    CPU=$1
    PREFIX=$(pwd)/$CPU
    PLATFORM=$2
    SYSROOT=$NDK_ROOT/platforms/android-24/arch-$CPU
    TOOLCHAIN=$NDK_ROOT/toolchains/$PLATFORM-4.9/prebuilt/darwin-x86_64

    $TOOLCHAIN/bin/$PLATFORM-ld \
    -rpath-link=$SYSROOT/usr/lib \
    -L$SYSROOT/usr/lib \
    -L$PREFIX/lib \
    -soname libffmpeg.so -shared -nostdlib -Bsymbolic --whole-archive --no-undefined -o \
    $PREFIX/libffmpeg.so \
    $CPU/lib/libavcodec.a \
    $CPU/lib/libavfilter.a \
    $CPU/lib/libavutil.a \
    $CPU/lib/libswresample.a \
    $CPU/lib/libavdevice.a \
    $CPU/lib/libavformat.a \
    $CPU/lib/libpostproc.a \
    $CPU/lib/libswscale.a \
    -lc -lm -lz -ldl -llog --dynamic-linker=/system/bin/linker \
    $TOOLCHAIN/lib/gcc/$PLATFORM/4.9.x/libgcc.a


    $TOOLCHAIN/bin/$PLATFORM-strip  $PREFIX/libffmpeg.so
}

build arm arm-linux-androideabi

build arm64 aarch64-linux-android

最终会生成一个libffmpeg.so,包大小狠狠的减少了。

2.FFmpeg接入openssl

先下载openssl库,https://www.openssl.org/source/snapshot/ 下载最新的:openssl-1.1.1-stable-SNAP-20200215.tar.gz openssl 库中编译配置是 ./Configure 文件,

openssl的编译选项有点少,我们需要将openssl编译到ffmpeg中,还是选择编译静态库,方便打包;

代码语言:javascript
复制
#!/bin/bash
export NDK_ROOT=/Users/jeffmony/tools/android-ndk-r14b # 修改自己本地的ndk路径

build() {
API=24
CPU=$1
PLATFORM=$2
make clean
rm -rf $(pwd)/android/$CPU
export ANDROID_NDK_HOME=$NDK_ROOT
PATH=$ANDROID_NDK_HOME/toolchains/$PLATFORM-4.9/prebuilt/darwin-x86_64/bin:$PATH
./Configure android-$CPU -D__ANDROID_API__=24 no-shared no-ssl2 no-ssl3 no-comp no-hw no-engine --prefix=$(pwd)/android/$CPU --openssldir=$(pwd)/android/$CPU

make
make install
}

# build armv7
build arm arm-linux-androideabi

# build armv8
build arm64 aarch64-linux-android

编译完成之后,会在android 文件夹下生成 arm、arm64两个文件夹;

  • include 下面是 openssl 的核心头文件;
  • lib 下面是编译好的 静态库;libcrypto.a和libssl.a

编译生成了.a库文件,我们在编译FFmpeg的时候将静态库链接进去,FFmpeg如果想解析https的链接,必须将openssl 编译进 FFmpeg 库中;

在编译ffmpeg的基础上加一些参数:

  • 编译配置中加上 --enable-openssl \ --enable-nonfree
  • 编译链接中加上openssl的链接:-extra-cflags 加上 openssl的头文件;--extra-ldflags 加上 openssl的静态库;
代码语言:javascript
复制
#!/bin/bash
export NDK_ROOT=/Users/jeffmony/tools/android-ndk-r14b # 修改自己本地的ndk路径

build() {
API=24
ARCH=$1
PLATFORM=$2
OPENSSL=$(pwd)/openssl/$ARCH
SYSROOT=$NDK_ROOT/platforms/android-$API/arch-$ARCH/
CROSS_PREFIX=$NDK_ROOT/toolchains/$PLATFORM-4.9/prebuilt/darwin-x86_64/bin/$PLATFORM-
PREFIX=$(pwd)/android/openssl/$ARCH #自己指定一个输出目录
rm -rf $(pwd)/android/openssl/$ARCH

echo "开始编译ffmpeg $ARCH so"
./configure \
--prefix=$PREFIX \
--disable-doc \
--enable-shared \
--disable-static \
--disable-x86asm \
--disable-asm \
--disable-symver \
--disable-devices \
--disable-avdevice \
--enable-gpl \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--enable-small \
--enable-openssl \
--enable-nonfree \
--enable-cross-compile \
--cross-prefix=$CROSS_PREFIX \
--target-os=android \
--arch=$ARCH \
--sysroot=$SYSROOT \
--extra-cflags="-I$OPENSSL/include -fPIE -pie" \
--extra-ldflags="-L$OPENSSL/lib"
}

# build armv7a
build arm arm-linux-androideabi
make clean
make -j4
make install

echo "完成ffmpeg $ARCH 编译..."

# build armv8a
build arm64 aarch64-linux-android
make clean
make -j4
make install

echo "完成ffmpeg $ARCH 编译..."

编译过程中发生如下的错误,找不到openssl; 去ffmpeg/configure 文件中查看一下:

报错的地方在这里,原因是新版本的openssl 需要在configure中新加一个检测语句:

代码语言:javascript
复制
check_lib openssl openssl/ssl.h OPENSSL_init_ssl -lssl -lcrypto

老的openssl库使用‘SSL_library_init’初始化, 新版本openssl使用‘OPENSSL_init_ssl’初始化;

下面正常编译就没有问题了;生成的ffmpeg中的so是可以解析https的。

3.FFmpeg接入x264

FFmpeg自带的h264的库性能一般,一般还是使用VideoLan实验室的x264库。首先下载x264 库;

代码语言:javascript
复制
git clone https://code.videolan.org/videolan/x264.git

不用切换分支,直接在master分支;因为需要编进ffmpeg中,所以还是编译静态库:

代码语言:javascript
复制
#!/bin/bash
export NDK_ROOT=/Users/jeffmony/tools/android-ndk-r14b # 修改自己本地的ndk路径

build() {
API=24
ARCH=$1
PLATFORM=$2
SYSROOT=$NDK_ROOT/platforms/android-$API/arch-$ARCH/
CROSS_PREFIX=$NDK_ROOT/toolchains/$PLATFORM-4.9/prebuilt/darwin-x86_64/bin/$PLATFORM-
PREFIX=$(pwd)/android/$ARCH #自己指定一个输出目录
rm -rf $(pwd)/android/$ARCH

if [ "$ARCH" == "arm" ];
then
    HOST=arm-linux
elif [ "$ARCH" == "arm64" ];
then
    HOST=aarch64-linux
fi

./configure \
--prefix=$PREFIX \
--host=$HOST \
--enable-pic \
--disable-asm \
--enable-static \
--cross-prefix=$CROSS_PREFIX \
--sysroot=$SYSROOT
}

# build armv7a
build arm arm-linux-androideabi
make clean
make -j4
make install

# build armv8a
build arm64 aarch64-linux-android
make clean
make -j4
make install

编译完成后,在android目录下生成不同平台的文件;生成头文件和对应的静态库;上面编译好了x264 静态库,ffmpeg需要加上特定的配置,--enable-libx264,--extra-cflags加上 x264的include头文件,--extra-ldflags加上x264的静态库:

代码语言:javascript
复制
#!/bin/bash
export NDK_ROOT=/Users/jeffmony/tools/android-ndk-r14b # 修改自己本地的ndk路径

build() {
API=24
ARCH=$1
PLATFORM=$2
X264=$(pwd)/x264/$ARCH
SYSROOT=$NDK_ROOT/platforms/android-$API/arch-$ARCH/
CROSS_PREFIX=$NDK_ROOT/toolchains/$PLATFORM-4.9/prebuilt/darwin-x86_64/bin/$PLATFORM-
PREFIX=$(pwd)/android/x264/$ARCH #自己指定一个输出目录
rm -rf $(pwd)/android/x264/$ARCH

echo "开始编译ffmpeg $ARCH so"
./configure \
--prefix=$PREFIX \
--disable-doc \
--enable-shared \
--disable-static \
--disable-x86asm \
--disable-asm \
--disable-symver \
--disable-devices \
--disable-avdevice \
--enable-gpl \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--enable-small \
--enable-libx264 \
--enable-cross-compile \
--cross-prefix=$CROSS_PREFIX \
--target-os=android \
--arch=$ARCH \
--sysroot=$SYSROOT \
--extra-cflags="-I$X264/include -fPIE -pie" \
--extra-ldflags="-L$X264/lib"
}

# build armv7a
build arm arm-linux-androideabi
make clean
make -j4
make install

echo "完成ffmpeg $ARCH 编译..."


# build armv8a
build arm64 aarch64-linux-android
make clean
make -j4
make install

echo "完成ffmpeg $ARCH 编译..."

本文所有的编译脚本都放在:https://github.com/JeffMony/AndroidFFmpegCompile,可以按照教程实践看一下。

另外我自己开发一个播放器,完全使用FFmpeg解封、解码和OpenGL ES来渲染:https://github.com/JeffMony/CustomPlayer

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-05-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 音视频平凡之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
SSL 证书
腾讯云 SSL 证书(SSL Certificates)为您提供 SSL 证书的申请、管理、部署等服务,为您提供一站式 HTTPS 解决方案。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档