使用FFmpeg

FFmpeg的强大之处就不多讲了,大家可以自行百度或者去 ffmpeg.org 去查看文档,libav.org 是从FFmpeg分裂出来的分支,有兴趣的可以去查一下相关历史。今天我要做的事情是这样的:

下载源码
使用NDK进行编译
Android项目中使用FFmpeg编译好的库
调用库函数
转码视频文件

在网上参考了很多文章,其中遇到了不少问题,现在把我编译集成的过程记录一下,供大家参考,也方便以后自己查阅。

我所使用的环境

OS : Mac OS X 10.11.2
Android IDE : Android Studio 2.0 Preview 3
NDK : android-ndk-r9d

1.下载FFmpeg源码

我使用了

下载后解压到自己的工程目录。我解压到了我库项目中 jni 目录下 文件夹名为 ffmpeg2.8.3。

为了直接编写测试程序,我直接新建了一个AS项目,在AS中的目录如下:
ffmpeg

1
2
3
4
|--app
|--ffmpegandroid
|--jni
|--ffmpeg2.8.3 //解压到这里

2.Mac环境下编译FFmpeg

在ffmpeg2.8.3目录下新建文件 build_config.sh
此shell脚本用来生成config.h并执行编译
如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/bin/bash
export TMPDIR=~/Android/temp #这句很重要,不然会报错 unable to create temporary file in
NDK=~/Android/android-ndk-r9d
SYSROOT=$NDK/platforms/android-14/arch-arm
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86_64
function build_one
{
./configure \
--prefix=$PREFIX \
--enable-shared \
--disable-static \
--disable-doc \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-avdevice \
--disable-doc \
--disable-symver \
--cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
--target-os=linux \
--arch=arm \
--enable-cross-compile \
--sysroot=$SYSROOT \
--extra-cflags="-I$SYSROOT/usr/include" \
# --extra-ldflags="-L$SYSROOT/usr/lib -nostdlib" \ #①这一句我注释掉了,不然会报 ld: -single_module: unknown option

$ADDITIONAL_CONFIGURE_FLAG
sed -i '' 's/HAVE_LRINT 0/HAVE_LRINT 1/g' config.h
sed -i '' 's/HAVE_LRINTF 0/HAVE_LRINTF 1/g' config.h
sed -i '' 's/HAVE_ROUND 0/HAVE_ROUND 1/g' config.h
sed -i '' 's/HAVE_ROUNDF 0/HAVE_ROUNDF 1/g' config.h
sed -i '' 's/HAVE_TRUNC 0/HAVE_TRUNC 1/g' config.h
sed -i '' 's/HAVE_TRUNCF 0/HAVE_TRUNCF 1/g' config.h
sed -i '' 's/HAVE_CBRT 0/HAVE_CBRT 1/g' config.h
sed -i '' 's/HAVE_RINT 0/HAVE_RINT 1/g' config.h

make clean
make -j4
make install
}
CPU=arm
PREFIX=$(pwd)/android/$CPU
ADDI_CFLAGS="-marm"
build_one

可能遇到的错误

1.unable to create temporary file in

脚本中加入,后面为临时路径,自己定义就好。要保证目录存在。
export TMPDIR=~/Android/temp

ld: -single_module: unknown option

应该是执行ld的参数传的不对,我注释掉就好了 见①
在网上找到了相关内容
Options.cpp
这应该是Mac中ld编译的相关代码Options.cpp应该是解析ld后面参数的类
我编译额时候,选择的ToolChian是darwin-x86_64,所以与Linux编译有点不一样。

error: static declaration of ‘xxxx’ follows non-static declaration

网上流传的解决方法是修改config.h文件,我个人不建议修改,脚本中下面这段可以免去修改解决问题。
这一段与Linux命令有不同之处,第一个空字符串是备份文件名,不写就是不需要备份,Linux里没有这个参数

1
2
3
4
5
6
7
8
sed -i '' 's/HAVE_LRINT 0/HAVE_LRINT 1/g' config.h
sed -i '' 's/HAVE_LRINTF 0/HAVE_LRINTF 1/g' config.h
sed -i '' 's/HAVE_ROUND 0/HAVE_ROUND 1/g' config.h
sed -i '' 's/HAVE_ROUNDF 0/HAVE_ROUNDF 1/g' config.h
sed -i '' 's/HAVE_TRUNC 0/HAVE_TRUNC 1/g' config.h
sed -i '' 's/HAVE_TRUNCF 0/HAVE_TRUNCF 1/g' config.h
sed -i '' 's/HAVE_CBRT 0/HAVE_CBRT 1/g' config.h
sed -i '' 's/HAVE_RINT 0/HAVE_RINT 1/g' config.h
libm.h:86:38: error: expected identifier or ‘(‘ before ‘sizeof’

解决这个问题是 将libm.h中所有的静态方法都注释掉。

1.arm-linux-androideabi-pkg-config not found

查看所有的引用路径,一定不要写错目录。

no include path in which to search for limits.h

应该也是路径问题。

编译通过

在 ffmpeg2.8.3 文件夹下会有编译好的库文件。