在前面的Linux下ndk编译移植FFmpeg到Android平台文章中介绍了如何将最基本的FFmpeg到Android平台。但只是简单的移植了FFmpeg,没有包含x264编码器,并且AAC编码器也只有默认的。在Android平台下使用FFmpeg进行RTMP推流(摄像头推流)中我实际上已经用到了x264编码器,但没有介绍如何将x264集成到FFmpeg中。而本篇文章将解决这个问题,重点讲解如何集成x264和libfdk-aac,当然也会有问题汇总。
为什么要单独一篇文章来介绍如何去移植FFmpeg、x264和fdk_aac呢?
万事开头难,第一步很难,但也是最重要的,不怕告诉大家,就仅仅编译这几个东西我足足花了两天时间去踩坑。对于有些编译出现各种问题导致没有成功的兄弟,可能非常的挫伤积极性,打击学习这方面知识的积极性。所以我觉得有必要重点讲解下这个环节
在进入这是内容之前我要强调一点,一定要注意安装版本,这个安装版本包括linux系统版本、FFmpeg版本、x264版本、libfdk-aac版本、ndk中android-api版本。你可能会因为版本不匹配导致编译出现各种问题,既然我已经把这些坑踩过了,希望大家不要再掉进去
同步开源库FFmpegSample,里面有我最新编译好的so
文章围绕以下几点介绍
- 编译环境
- x264编译
- libfdk-aac编译
- FFmpeg 编译
- 踩坑历程
编译环境
- linux版本 centos 6.8_64位
[root@iZ94g6hanmqZ include]# lsb_release -a
LSB Version: :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch
Distributor ID: CentOS
Description: CentOS release 6.8 (Final)
Release: 6.8
Codename: Final
- ndk版本 下载最新即可
我的安装位置在/usr/local/android/ndk-bundle
接下来到了真正编译的时候了,注意我做编译的目录在/opt/下,也就是所有的源码都解压在这个目录下
编译x264
下载地址下载版本x264-snapshot-20140916-2245-stable.tar
然后解压为x264目录,进入x264目录,新建
build_x264.sh
内容为:
#!/bin/bash
NDK=/usr/local/android/ndk-bundle
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
PLATFORM=$NDK/platforms/android-16/arch-arm
PREFIX=./android
function build_one
{
./configure \
--prefix=$PREFIX \
--enable-static \
--disable-shared \
--enable-pic \
--disable-asm \
--disable-cli \
--host=arm-linux \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--sysroot=$PLATFORM
}
build_one
然后给文件增加运行权限 chmod +x build_x264.sh
。剩下的就是配置编译安装啦。
./build_x264.sh
make -j4
make install
安装目录就在当前目录下生成android目录,当然库文件和头文件就有了
drwxr-xr-x 2 root root 4096 Jan 25 15:06 include
drwxr-xr-x 3 root root 4096 Jan 25 15:06 lib
编译libfdk-aac
先来几个问题:
- 为啥要集成libfdk-aac呢?
嘿嘿!别着急,这个我会在下篇文章介绍ffmpeg进行AAC编码时候讲到,这里我只讲如何编译。
- 为啥要集成libfdk-aac呢?
- 为什么不集成libfaac?
不少尝试过的童鞋会发现,在编译FFmpeg时集成libfaac也就是configure增加--enable-libfaac
参数时会提示ffmpeg: remove option for libfaac,Unknown option "--enable-libfaac"
,因为现在FFmpeg不支持libfaac扩展了。而网上很多比较早期的文章都是讲如何集成libfaac的,所以很多童鞋就比较疑惑。
- 为什么不集成libfaac?
下面正式进入编译fdk_aac
下载地址版本选择0.1.4
同样加压到fdk-aac-0.1.4目录,进入目录,新建
build_fdk.sh
内容为:
NDK=/usr/local/android/ndk-bundle
ANDROID_API=android-14
SYSROOT=$NDK_HOME/platforms/$ANDROID_API/arch-arm
ANDROID_BIN=$NDK_HOME/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/
CROSS_COMPILE=${ANDROID_BIN}/arm-linux-androideabi-
ARM_INC=$SYSROOT/usr/include
ARM_LIB=$SYSROOT/usr/lib
LDFLAGS=" -nostdlib -Bdynamic -Wl,--whole-archive -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,nocopyreloc -Wl,-soname,/system/lib/libz.so -Wl,-rpath-link=$ARM_LIB,-dynamic-linker=/system/bin/linker -L$NDK_HOME/sources/cxx-stl/gnu-libstdc++/libs/armeabi -L$NDK_HOME/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86/arm-linux-androideabi/lib -L$ARM_LIB -lc -lgcc -lm -ldl "
FLAGS="--host=arm-androideabi-linux --enable-static --disable-shared"
export CXX="${CROSS_COMPILE}g++ --sysroot=${SYSROOT}"
export LDFLAGS="$LDFLAGS"
export CC="${CROSS_COMPILE}gcc --sysroot=${SYSROOT}"
./configure $FLAGS --prefix='/opt/fdk-aac-0.1.4/android'
剩下的就是配置编译安装啦。
./build_fdk.sh
make -j4
make install
安装目录就在当前目录下生成android目录,当然库文件和头文件就有了
drwxr-xr-x 2 root root 4096 Jan 25 15:06 include
drwxr-xr-x 3 root root 4096 Jan 25 15:06 lib
编译FFmpeg
FFmpeg版本3.2.4 下载地址
下载完源码解压后,我们进入目录新建build_ffmpeg.sh
脚本,内容
#!/bin/bash
NDK=/usr/local/android/ndk-bundle
SYSROOT=$NDK/platforms/android-16/arch-arm/
PREBUILT=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
function build_one
{
./configure --prefix=$PREFIX \
--enable-shared \
--cc=$TOOLCHAIN/bin/arm-linux-androideabi-gcc \
--disable-static \
--disable-doc \
--disable-ffserver \
--disable-yasm \
--enable-cross-compile \
--enable-gpl \
--enable-libx264 \
--enable-decoder=h264 \
--enable-encoder=libx264 \
--enable-libfdk-aac \
--enable-encoder=libfdk_aac \
--enable-decoder=libfdk_aac \
--enable-nonfree \
--cross-prefix="$TOOLCHAIN/bin/arm-linux-androideabi-" \
--target-os=linux \
--arch=arm \
--sysroot=$SYSROOT \
--extra-cflags="-Os -fpic $ADDI_CFLAGS" \
--extra-ldflags="$ADDI_LDFLAGS" \
$ADDITIONAL_CONFIGURE_FLAG
}
CPU=arm
PREFIX=$(pwd)/android/$CPU
ADDI_CFLAGS="-marm -I/opt/x264/android/include -DANDROID -I/opt/fdk-aac-0.1.4/android/include"
ADDI_LDFLAGS="-L/opt/x264/android/lib -L/opt/fdk-aac-0.1.4/android/lib"
build_one
然后给文件增加运行权限 chmod +x build_ffmpeg.sh
。剩下的就是配置编译安装啦。
./build_x264.sh
make -j4
make install
安装完之后我们最终的so包就生成了。在当前目录下的 ./android/arm下。
drwxr-xr-x 2 root root 4096 Jan 25 15:23 bin
drwxr-xr-x 10 root root 4096 Jan 25 15:11 include
drwxr-xr-x 3 root root 4096 Jan 25 15:23 lib
drwxr-xr-x 3 root root 4096 Jan 25 15:11 share
我们的动态库就在lib下了
-rwxr-xr-x 1 root root 12983912 Jan 25 15:23 libavcodec-57.so
lrwxrwxrwx 1 root root 16 Jan 25 15:23 libavcodec.so -> libavcodec-57.so
-rwxr-xr-x 1 root root 59384 Jan 25 15:23 libavdevice-57.so
lrwxrwxrwx 1 root root 17 Jan 25 15:23 libavdevice.so -> libavdevice-57.so
-rwxr-xr-x 1 root root 1877548 Jan 25 15:23 libavfilter-6.so
lrwxrwxrwx 1 root root 16 Jan 25 15:23 libavfilter.so -> libavfilter-6.so
-rwxr-xr-x 1 root root 1956464 Jan 25 15:23 libavformat-57.so
lrwxrwxrwx 1 root root 17 Jan 25 15:23 libavformat.so -> libavformat-57.so
-rwxr-xr-x 1 root root 443860 Jan 25 15:23 libavutil-55.so
lrwxrwxrwx 1 root root 15 Jan 25 15:23 libavutil.so -> libavutil-55.so
-rwxr-xr-x 1 root root 42276 Jan 25 15:23 libpostproc-54.so
lrwxrwxrwx 1 root root 17 Jan 25 15:23 libpostproc.so -> libpostproc-54.so
-rwxr-xr-x 1 root root 91532 Jan 25 15:23 libswresample-2.so
lrwxrwxrwx 1 root root 18 Jan 25 15:23 libswresample.so -> libswresample-2.so
-rwxr-xr-x 1 root root 406924 Jan 25 15:23 libswscale-4.so
lrwxrwxrwx 1 root root 15 Jan 25 15:23 libswscale.so -> libswscale-4.so
drwxr-xr-x 2 root root 4096 Jan 25 15:23 pkgconfig
这里对脚本做个解释,增加了几个命令。
- 支持x264扩展
--enable-libx264 \
--enable-decoder=h264 \
--enable-encoder=libx264 \
- 支持fdk_aac扩展
--enable-libfdk-aac \
--enable-encoder=libfdk_aac \
--enable-decoder=libfdk_aac \
要支持fdk_aac必须还加上
--enable-nonfree \
--enable-gpl \
最后就是制定x264 fdk_aac的头文件和库文件的目录--extra-cflags
加入头文件目录,--extra-ldflags
包含库文件目录,也就是
ADDI_CFLAGS="-marm -I/opt/x264/android/include -DANDROID -I/opt/fdk-aac-0.1.4/android/include"
ADDI_LDFLAGS="-L/opt/x264/android/lib -L/opt/fdk-aac-0.1.4/android/lib"
到这里我们就完成了整个编译。得到的so库不仅有FFmpeg基础功能,还有x264和fdk_aac的编解码功能
踩坑历程
configure FFmpeg提示找不到x264
看到这个问题,我开始很诧异,我明明都配置正确了,后来查看config日志,提示 找不到什么log2方法。后来发现新版本的x264的config.h中启用了这个方法,所以大家按我选择的版本就没问题啦。
make FFmpeg 报错
libavcodec/libx264.c: In function 'x264_frame' :
libavcodec/libx264.c:282:9 error: 'x264_bit_depth' undeclared(first use in this function)
if(x264_bit_depth>8)
libavcodec/libx264.c: In function 'x264_init_static':
libavcodec/libx264.c:892.9 error: 'x264_bit_depth' undeclared(first use in this function)
if(x264_bit_depth== 8)
很明显没有找到x264_bit_depth这个变量。那咋办,还是版本不对应咯。你用的x264,FFmpeg可能不太兼容哦。
configure FFmpeg是faac不能用
这个前面已经提到了,FFmpeg已经不再支持libfaac啦。
编译好的so ,放在android平台下使用时,提示找不到x264.so
这里要注意,我在编译x264和fdk_aac时全部使用的静态编译,编出来的是静态库。那么最终我编译完FFmpeg后就不需要讲x264的so加入到android应用项目中。如果你是动态编译x264和fdk_aac那么你就得把这两个库的so也加入到android应用项目中。
注意编译x264和fdk_aac中间的参数--enable-static --disable-shared
到此所有讲解结束了,先预告下一篇,下一篇将介绍Android平台下使用FFmpeg进行AAC编译。里面会给大家解释为什么要用fdk_aac,而不用默认的AAC编码器。
网友评论
See `config.log' for more details
还有个疑问:
在你的脚本中有这个路径:
-L$NDK_HOME/sources/cxx-stl/gnu-libstdc++/libs/armeabi
我本地是这样的:-L$NDK_HOME/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi
难道没报错吗?
```
Makefile:227: recipe for target '.depend' failed
make: *** [.depend] Error 1
/home/hong/Android/Sdk/ndk-bundle/toolchains/x86_64-4.9/prebuilt/linux-x86_64/bin/x86_64-linux-android-gcc -Wno-maybe-uninitialized -Wshadow -O3 -ffast-math -m64 -Wall -I. -I. --sysroot=/home/hong/Android/Sdk/ndk-bundle/platforms/android-21/arch-x86_64/ -Os -fpic -std=gnu99 -D_GNU_SOURCE -mpreferred-stack-boundary=5 -fPIC -fomit-frame-pointer -fno-tree-vectorize -c -o x264.o x264.c
x264.c:40:20: fatal error: signal.h: No such file or directory
#include <signal.h>
^
compilation terminated.
<builtin>: recipe for target 'x264.o' failed
make: *** [x264.o] Error 1
/home/hong/Android/Sdk/ndk-bundle/toolchains/x86_64-4.9/prebuilt/linux-x86_64/bin/x86_64-linux-android-gcc -Wno-maybe-uninitialized -Wshadow -O3 -ffast-math -m64 -Wall -I. -I. --sysroot=/home/hong/Android/Sdk/ndk-bundle/platforms/android-21/arch-x86_64/ -Os -fpic -std=gnu99 -D_GNU_SOURCE -mpreferred-stack-boundary=5 -fPIC -fomit-frame-pointer -fno-tree-vectorize -c -o x264.o x264.c
x264.c:40:20: fatal error: signal.h: No such file or directory
#include <signal.h>
^
compilation terminated.
<builtin>: recipe for target 'x264.o' failed
make: *** [x264.o] Error 1
```
我发现signal.h文件老版本的NDK是在
ndk-bundle/platforms/android-14/arch-arm/usr/include文件夹目录下
而现在最新版本的NDK signal.h文件是在
ndk-bundle-sysroot-usr-include 文件夹目录下,
哪在配置这个路径的时候SYSROOT=$NDK_HOME/platforms/$ANDROID_API/arch-x86_64 应该怎么写呀,还是按照原来的这样写吗。