iOS: FFmpeg编译和使用问题总结
折磨了我近一周多时间的FFmpeg库编译问题终于解决了,必须得把这一段时间来遇到过的坑全写出来。如果急着解决问题,编译最新版本的FFmpeg库请直接看第二部分,编译较老版本(0.7)的FFmpeg库请直接跳至第七部分,那里有你想要的编译脚本,但别忘了抽空看看全文。
一、背景
网上有很多FFmpeg编译配置的资料,大部分都是关于FFmpeg最新的版本(2.0)的,我一开始也想着编写一个2.0版本的,可以放到接手的那个项目中,发现各种问题(无法快进,没有声音),再看一下代码一堆警告,原因很简单,使用的FFMpeg库太新了,很多接口变动了。由于手上没有多少信息,不知道那个项目使用的是哪个版本的FFmpeg库,一点点找,终于知道原来使用的是0.7.x的。找到目标版本的FFmpeg本以为万事大吉了,后来才发现原来这才是坑的开始,有历经一系列磨难,最后终于把编译问题解决了。
二、FFmpeg最新版本的库编译
FFmpeg最新版本的应该是2.1的,历史版本详见http://www.ffmpeg.org/releases/,在这个网站上我们可以下到所有历史版本的库。FFmpeg是一个跨平台的用C语言写成的库,包含了编码,解码,色彩空间转换等库。编译需要用到命令行,对于我们这些没搞过后台或者linux开发的脚本知识欠缺的人来说的确算是一个挑战。庆幸的是现在网络这么方便,不会做问Google,很快就找到了一个在xcode5下一键编译FFmpeg库的脚本。这个脚本是个老外写的,真心强大,从下载到编译到构建最后的Fat库一气呵成。
脚本地址: https://gist.github.com/m1entus/6983547
运行这个脚本需要依赖一个库Perl写的脚本,搜了一下网上目前编译FFmpeg库的帖子基本都会提到这个脚本,脚本地址如下: https://github.com/mansr/gas-preprocessor。
下载完这两个脚本后,编译FFmpeg库的准备工作就基本完成了,接着依次执行下面几步:
1、拷贝gas-preprocessor.pl文件到 /usr/bin目录下。
2、修改gas-preprocessor.pl文件的权限
注:需要有读,写和执行的权限。具体操作为,首先在命令行下进入/usr/bin目录,然后执行chmod命令,如下图所示:
3、切换build-ffmpeg.sh脚本的目录下,使用命令sh build-ffmpeg.sh 运行该脚本即可。
注: 1) build-ffmpeg.sh脚本的父目录的名字不能包括空格,否则可能导致构建失败。
2) build-ffmpeg.sh脚本中可以配置编译的FFMpeg版本,以及使用iOS SDK的版本,如下图所示:
该脚本中默认采用的FFmpeg是2.0版本,使用iOS 7.0的SDK编译,c语言编译器采用clang,应用中可以根据实际项目需要选中不同的FFmpeg和iOS SDK版本。
根据上面的步骤看来,编译工作也没有什么复杂的,为什么我会说踩了很多坑呢?这个问题我会一点点儿解释。
三、编译较早期版本的FFmpeg本库
第二部分中我们介绍了一个牛逼的脚本,一键编译,这给我们造成了一种错觉,FFmpeg编译不过如此吗!如果我们尝试一下把脚本中的VERSION变成0.7试试,运行脚本,发现编译报错。如下图所示:
提示位置选项--disable-iconv,根据提示我们输入./configure查看所有可用选项。命令行下切换到实际的FFmpeg源码目录下,查看帮助如下图:
我们可以看到很多选项,英语不难,就是有些选项描述的太简洁了,所以实际使用时如果不确定的话,我们可以去问问google。
好了回过头来看看这个configure文件到底有什么作用呢?
1、裁剪
我们知道FFmpeg库是一个非常庞大的库,包括编码,解码以及流媒体的支持等,如果不做裁剪全部编译进来的话,最后生成的静态库会很大。实际使用中我们可能只想用到解码(例如播放器),因此我们可以使用相关选项指定编译时禁用编码部分。当然我们还可以做进一步的裁剪,例如只打开部分常用格式的解码,禁用掉其他的解码,这样编译出来的静态库将会更小。
要想裁剪,我们的先知道有哪些部分,使用下面的命令可以查看FFMpeg库支持的组件列表。
--list-decoders show all available decoders --list-encoders show all available encoders --list-hwaccels show all available hardware accelerators --list-muxers show all available muxers --list-demuxers show all available demuxers --list-parsers show all available parsers --list-protocols show all available protocols --list-bsfs show all available bitstream filters --list-indevs show all available input devices --list-outdevs show all available output devices --list-filters show all available filters
我们可以根据实际需要把不用的部分都禁用掉,这样编译快,包也会比较小,常用的裁剪选项如下:
--disable-doc do not build documentation --disable-ffmpeg disable ffmpeg build --disable-ffplay disable ffplay build --disable-ffserver disable ffserver build --disable-network disable network support [no] --disable-encoder=NAME disable encoder NAME --enable-encoder=NAME enable encoder NAME --disable-encoders disable all encoders --disable-decoder=NAME disable decoder NAME --enable-decoder=NAME enable decoder NAME --disable-decoders disable all decoders --disable-hwaccel=NAME disable hwaccel
举个例子,如果我们需要做一款本地视频播放器,那么我们可以使用如下配置:
当然你还可以根据帮助列表进行更细粒度的裁剪,例如只支持哪几种格式的解码等等。
2、指定编译环境
FFMpeg作为一个跨平台的库,不同的平台,不同的人的计算机上编译器的路径都可能不尽相同,所以我们需要为编译脚本指定编译器的路径。同事我们还可以指定其他编译选项,如是否交叉编译,目标平台系统,CPU架构,需要依赖的其他库的路径已经指定是否禁用汇编优化等。
--enable-cross-compile assume a cross-compiler is used
--sysroot=PATH root of cross-build tree
--sysinclude=PATH location of cross-build system headers
--target-os=OS compiler targets OS []
--cc=CC use C compiler CC [gcc]
--extra-cflags=ECFLAGS add ECFLAGS to CFLAGS []
--extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS []
--arch=ARCH select architecture []
--cpu=CPU select the minimum required CPU (affects
instruction selection, may crash on older CPUs)
--disable-asm disable all assembler optimizations
sysroot即iOS SDK的路径,注意编译真机版本的库时需要使用iPhoneOS.platform中SDK的路径,编译模拟器版本的库使用iPhoneSimulator.platform中SDK的路径。target-os填写darwin(苹果系统的内核),arch可以根据具体的情况添加i386(模拟器),armv6,armv7等。cpu根据具体类型可填写cortex-a8,cortox-a9,i386等。
3、指定静态库的安装路径
指定执行make install命令时编译好的静态库和相关头文件拷贝到的位置,即FFmpeg库编译后输出的路径。通常我们只需要设置“--prefix=PREFIX”选项即可。例如我们需要将最后生成静态库的路径指向“build/armv7”下,则设置--prefix="build/armv7";
四、FFmpeg0.7版本库一键编译脚本
通过第三部分的介绍,相信我们应该对FFmpeg的配置都有了一个初步的认识,我们再回到第三部分开始时我们运行build-ffmpeg.sh的碰到的问题,经过查看configure的帮助,我们发现0.7这个版本的FFmpeg库却是没有"--disable-iconv"选项。这个牛逼的脚本是针对当前较新的FFmpeg库写的,在低版本中没有一些配置选项也是正常。
下面给出经过修改后的脚本,脚本中对原先的脚本进行了精简,去掉了下载部分的代码。
#!/bin/sh ######################################################################## ##################### copyright by smileEvday ########################## ##################### smileEvday.cnblogs.com ########################### ######################################################################## # FFMpeg,SDK版本号 VERSION="0.7.4" SDKVERSION="6.1" #最低支持的SDK版本号 MINSDKVERSION="5.0" # 源文件路径 SRCDIR=$(pwd) BUILDDIR="${SRCDIR}/build" mkdir -p $BUILDDIR # 获取xcode开发环境安装路径 DEVELOPER=`xcode-select -print-path` # 要编译的架构列表 ARCHS="armv7 armv7s i386" for ARCH in ${ARCHS} do if [ "${ARCH}" == "i386" ]; then PLATFORM="iPhoneSimulator" EXTRA_CFLAGS="-arch i386" EXTRA_LDFLAGS="-arch i386 -mfpu=neon" EXTRA_CONFIG="--arch=i386 --cpu=i386" else PLATFORM="iPhoneOS" EXTRA_CFLAGS="-arch ${ARCH} -mfloat-abi=softfp" EXTRA_LDFLAGS="-arch ${ARCH} -mfpu=neon -mfloat-abi=softfp" EXTRA_CONFIG="--arch=arm --cpu=cortex-a9 --disable-armv5te" fi make clean # you can do any clip here ./configure --prefix="${BUILDDIR}/${ARCH}" \ --disable-doc \ --disable-ffmpeg \ --disable-ffplay \ --disable-ffserver \ --enable-cross-compile \ --enable-pic \ --disable-asm \ --target-os=darwin \ ${EXTRA_CONFIG} \ --cc="${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer/usr/bin/gcc" \ --as="/usr/bin/gas-preprocessor.pl" \ --sysroot="${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer/SDKs/${PLATFORM}${SDKVERSION}.sdk" \ --extra-cflags="-miphoneos-version-min=${MINSDKVERSION} ${EXTRA_CFLAGS}" \ --extra-ldflags="-miphoneos-version-min=${MINSDKVERSION} ${EXTRA_LDFLAGS} -isysroot ${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer/SDKs/${PLATFORM}${SDKVERSION}.sdk" make && make install && make clean done ######################################################################################################################## ##################################################### 生成fat库 ######################################################### ######################################################################################################################## mkdir -p ${BUILDDIR}/universal/lib cd ${BUILDDIR}/armv7/lib for file in *.a do cd ${SRCDIR}/build xcrun -sdk iphoneos lipo -output universal/lib/$file -create -arch armv7 armv7/lib/$file -arch armv7s armv7s/lib/$file -arch i386 i386/lib/$file echo "Universal $file created." done cp -r ${BUILDDIR}/armv7/include ${BUILDDIR}/universal/ echo "Done."