在Android下编译ffmpeg+x264+libfdk-aac的常见问题和解决方法
2017-05-22 19:50
706 查看
搞多媒体开发的对ffmpeg、libfdk-aac、x264这几个库应该都比较熟悉,在此不多做介绍。最近公司需要升级多媒体库,第一步工作就是将ffmpeg+x264+libfdk-aac移植到Android平台。关于ffmpeg+libfdk-aac+x264的交叉编译步骤,网上相关的内容很多。不过由于ffmpeg的配置选项丰富,在网上查到的脚本几乎都不符合我们的需求,了解ffmpeg的编译过程后自己写了个脚本,进行简单修改后就可以对不同的CPU架构和Android API level生成不同的二进制文件。去掉公司的业务代码后,我把编译脚本和相应的开源库放到了github上,欢迎大家前去围观。github地址:https://github.com/x5miao/ffmpeg-android
和交叉编译相关的脚本主要包括项目目录下的set-build.sh,ffmpeg/config-android.sh, x264/config-android.sh, libfdk-aac/config-android.sh。set-build.sh主要用来设置环境变量,以及根据命令行启动不同组件的configure和编译过程。几个config-android.sh主要就是调用开源库里自带的configure脚本进行配置生成makefile文件,然后调用make生成静态库文件。
最重要的脚本就是set-build.sh,其主要内容如下所示:
#!/bin/bash
#本脚本用于设置交叉编译环境并编译libmedia各子模块,用户请根据自身的编译环境修改
#相应的环境变量.
#libmedia的编译仅在ubuntu下测试通过,推荐使用ubuntu14.04-64TLS.
#注意:不要使用cygwin编译,否则可能出现无法编译的bug.
#set -x
LIBMEDIA_TARGET_PLATFORM=android-22
LIBMEDIA_TARGET_ARCH_ABI=arm64-v8a #armeabi-v7a armeabi
#NDK_ROOT_PATH指向Android NDK开发包的根路径
NDK_ROOT_PATH=/home/xxm/android_dev/android-ndk-r13b
#TOOLCHAIN版本号,请参考${NDK_ROOT_PATH}/toolchains目录下的文件夹名字修改
TOOLCHAIN_VERSION=4.9
#TMPDIR用来指定ffmpeg编译过程中间生成文件的保存目录,编译时请根据用户自己的本地环境指定,
#编译前必须保证该temp文件夹存在
FFMPEG_TMPDIR=/home/xxm/android_dev/workspace/tmp
export LIBMEDIA_TARGET_PLATFORM LIBMEDIA_TARGET_ARCH_ABI FFMPEG_TMPDIR NDK_ROOT_PATH TOOLCHAIN_VERSION
#编译ffmpeg需要按照Android开发者论团的介绍先建立离线交叉编译工具链
#参考网址:https://developer.android.com/ndk/guides/standalone_toolchain.html#wwc
#STANDLONE_ROOT_PATH=/home/xxm/android_dev/workspace/arm-linux-androideabi
#export STANDLONE_ROOT_PATH
#set +x
print_helpmsg(){
echo "usage:source set-env.sh [option]"
echo "option is:"
printf "\t all: rebuild all opensource library and interface files(GGCodec*.c)\n"
printf "\t x264: rebuild x264 and interface files\n"
printf "\t libfdk-aac: rebuild libfdk-aac and interface files\n"
printf "\t ffmpeg: rebuild ffmpeg and interface files\n"
printf "\t help: print this message\n\n"
}
build_x264(){
cd x264 && ./config-android.sh && cd ..
}
build_libfdk-aac(){
cd libfdk-aac && ./config-android.sh && cd ..
}
build_ffmpeg(){
cd ffmpeg && ./config-android.sh $1 && cd ..
}
build_module(){
cp out/Android.mk out/${LIBMEDIA_TARGET_ARCH_ABI}/
ndk-build clean && ndk-build all
}
build(){
if test "$1" = "all"; then
build_x264 && build_libfdk-aac && build_ffmpeg 2
elif test "$1" = "x264"; then
build_x264 && build_ffmpeg 2
elif test "$1" = "libfdk-aac"; then
build_libfdk-aac && build_ffmpeg 2
elif test "$1" = "ffmpeg"; then
build_ffmpeg 2
elif test "$1" = "help"; then
print_helpmsg && eixt 0
else
printf "no option, just rebuild interface files\n\n" && print_helpmsg
fi
if test $? -eq 0;then
build_module
fi
}
build "$@"
set-build.sh通过如下方式调用:
如果需要修改目标平台的ABI和Platform,请修改LIBMEDIA_TARGET_ARCH_ABI和LIBMEDIA_TARGET_PLATFORM两个环境变量,修改这两个变量中任何一个之后必须重新用all选项重新编译所有组件。
交叉编译的时候遇到一些坑,分享出来希望对其他人有所帮助。
(1) 编译ffmpeg时提示找不到libfdk-aac或libx264。这个问题是由于ffmpeg时交叉编译器找不到libfdk-aac/x264的头文件或静态库.a文件导致的。解决方法是将ffmpeg、libfdk-aac、libx264的--prefix选项赋值为相同的目录,并给configure脚本加上--extra-cflags=“-I${PREFIX}/include”和--extra-ldflags=“-L${PREFIX}/lib -lx264 -lfdk-aac”选项。编写脚本时注意libfdk-aac(小短线)和libfdk_aac(下划线)的区别,configure有时候需要是短线版本有时候又需要下划线版本,容易搞错。
(2) 编译了32位so文件后再编译64位so文件时,提示strtod.o的文件格式不对。这是由于对于3.2版本的ffmpeg,make clean不会删除compat下的strtod.o,strtod.d, msvcrt/snprintf.o, msvcrt/snprintf.d四个文件,只要手动删除后重新编译即可。具体可以参考简书上esonyf的这篇文章:http://www.jianshu.com/p/612ef67e42bd
(3) 调用avodec_find_decoder|encoder(AVCODEC_ID_AAC|AVCODEC_ID_H264)返回失败。造成这个问题的原因是虽然动态库里面包含了libfdk-aac和x264编解码相关的代码,却没有将其注册到ffmpeg。解决方法是configure时通过--enable-encoder=libx264|libfdk_aac选项显示启用libfdk-aac和libx264作为编解码器。
(4) configure时有时候会遇到‘C Compiler is not working’之类的错误,但是交叉编译器明显就在正确的路劲下。因为这个问题耽误了大半天的时间,后来通过分析config.log才发现当configure时如果指定了错误的编译链接选项,比如--arch指定了configure脚本不识别的体系架构、--extra-cflags里面指定了不支持的编译器选项,或者--extra-ldflags里有--nostdlib之类的选项,导致交叉编译器在测试生成可执行文件命令后返回了非0值,
configure脚本就会打印出这个很有误导性的消息。对于ffmpeg可以通过分析configure的输出日志文件config.log来定位问题。不过x264的configure脚本生成的config.log里面却得不到任何线索,只能通过在其configure脚本开头添加set -x调试选项来跟踪configure脚本的执行来排查问题了。这也提醒我们,不管是写脚本或者程序文件是错误报告消息的重要性,不准确的日志消息太有误导性了。
和交叉编译相关的脚本主要包括项目目录下的set-build.sh,ffmpeg/config-android.sh, x264/config-android.sh, libfdk-aac/config-android.sh。set-build.sh主要用来设置环境变量,以及根据命令行启动不同组件的configure和编译过程。几个config-android.sh主要就是调用开源库里自带的configure脚本进行配置生成makefile文件,然后调用make生成静态库文件。
最重要的脚本就是set-build.sh,其主要内容如下所示:
#!/bin/bash
#本脚本用于设置交叉编译环境并编译libmedia各子模块,用户请根据自身的编译环境修改
#相应的环境变量.
#libmedia的编译仅在ubuntu下测试通过,推荐使用ubuntu14.04-64TLS.
#注意:不要使用cygwin编译,否则可能出现无法编译的bug.
#set -x
LIBMEDIA_TARGET_PLATFORM=android-22
LIBMEDIA_TARGET_ARCH_ABI=arm64-v8a #armeabi-v7a armeabi
#NDK_ROOT_PATH指向Android NDK开发包的根路径
NDK_ROOT_PATH=/home/xxm/android_dev/android-ndk-r13b
#TOOLCHAIN版本号,请参考${NDK_ROOT_PATH}/toolchains目录下的文件夹名字修改
TOOLCHAIN_VERSION=4.9
#TMPDIR用来指定ffmpeg编译过程中间生成文件的保存目录,编译时请根据用户自己的本地环境指定,
#编译前必须保证该temp文件夹存在
FFMPEG_TMPDIR=/home/xxm/android_dev/workspace/tmp
export LIBMEDIA_TARGET_PLATFORM LIBMEDIA_TARGET_ARCH_ABI FFMPEG_TMPDIR NDK_ROOT_PATH TOOLCHAIN_VERSION
#编译ffmpeg需要按照Android开发者论团的介绍先建立离线交叉编译工具链
#参考网址:https://developer.android.com/ndk/guides/standalone_toolchain.html#wwc
#STANDLONE_ROOT_PATH=/home/xxm/android_dev/workspace/arm-linux-androideabi
#export STANDLONE_ROOT_PATH
#set +x
print_helpmsg(){
echo "usage:source set-env.sh [option]"
echo "option is:"
printf "\t all: rebuild all opensource library and interface files(GGCodec*.c)\n"
printf "\t x264: rebuild x264 and interface files\n"
printf "\t libfdk-aac: rebuild libfdk-aac and interface files\n"
printf "\t ffmpeg: rebuild ffmpeg and interface files\n"
printf "\t help: print this message\n\n"
}
build_x264(){
cd x264 && ./config-android.sh && cd ..
}
build_libfdk-aac(){
cd libfdk-aac && ./config-android.sh && cd ..
}
build_ffmpeg(){
cd ffmpeg && ./config-android.sh $1 && cd ..
}
build_module(){
cp out/Android.mk out/${LIBMEDIA_TARGET_ARCH_ABI}/
ndk-build clean && ndk-build all
}
build(){
if test "$1" = "all"; then
build_x264 && build_libfdk-aac && build_ffmpeg 2
elif test "$1" = "x264"; then
build_x264 && build_ffmpeg 2
elif test "$1" = "libfdk-aac"; then
build_libfdk-aac && build_ffmpeg 2
elif test "$1" = "ffmpeg"; then
build_ffmpeg 2
elif test "$1" = "help"; then
print_helpmsg && eixt 0
else
printf "no option, just rebuild interface files\n\n" && print_helpmsg
fi
if test $? -eq 0;then
build_module
fi
}
build "$@"
set-build.sh通过如下方式调用:
source set-build.sh [all|ffmpeg|x264|libfdk-aac|help] all: 所有组件都重新构建; ffmpeg:重新构建ffmpeg的静态库; x264:重新构建x264和ffmpeg; libfdk-aac:重新构建libfdk-aac和ffmpeg; help:打印command的帮助信息。
如果需要修改目标平台的ABI和Platform,请修改LIBMEDIA_TARGET_ARCH_ABI和LIBMEDIA_TARGET_PLATFORM两个环境变量,修改这两个变量中任何一个之后必须重新用all选项重新编译所有组件。
交叉编译的时候遇到一些坑,分享出来希望对其他人有所帮助。
(1) 编译ffmpeg时提示找不到libfdk-aac或libx264。这个问题是由于ffmpeg时交叉编译器找不到libfdk-aac/x264的头文件或静态库.a文件导致的。解决方法是将ffmpeg、libfdk-aac、libx264的--prefix选项赋值为相同的目录,并给configure脚本加上--extra-cflags=“-I${PREFIX}/include”和--extra-ldflags=“-L${PREFIX}/lib -lx264 -lfdk-aac”选项。编写脚本时注意libfdk-aac(小短线)和libfdk_aac(下划线)的区别,configure有时候需要是短线版本有时候又需要下划线版本,容易搞错。
(2) 编译了32位so文件后再编译64位so文件时,提示strtod.o的文件格式不对。这是由于对于3.2版本的ffmpeg,make clean不会删除compat下的strtod.o,strtod.d, msvcrt/snprintf.o, msvcrt/snprintf.d四个文件,只要手动删除后重新编译即可。具体可以参考简书上esonyf的这篇文章:http://www.jianshu.com/p/612ef67e42bd
(3) 调用avodec_find_decoder|encoder(AVCODEC_ID_AAC|AVCODEC_ID_H264)返回失败。造成这个问题的原因是虽然动态库里面包含了libfdk-aac和x264编解码相关的代码,却没有将其注册到ffmpeg。解决方法是configure时通过--enable-encoder=libx264|libfdk_aac选项显示启用libfdk-aac和libx264作为编解码器。
(4) configure时有时候会遇到‘C Compiler is not working’之类的错误,但是交叉编译器明显就在正确的路劲下。因为这个问题耽误了大半天的时间,后来通过分析config.log才发现当configure时如果指定了错误的编译链接选项,比如--arch指定了configure脚本不识别的体系架构、--extra-cflags里面指定了不支持的编译器选项,或者--extra-ldflags里有--nostdlib之类的选项,导致交叉编译器在测试生成可执行文件命令后返回了非0值,
configure脚本就会打印出这个很有误导性的消息。对于ffmpeg可以通过分析configure的输出日志文件config.log来定位问题。不过x264的configure脚本生成的config.log里面却得不到任何线索,只能通过在其configure脚本开头添加set -x调试选项来跟踪configure脚本的执行来排查问题了。这也提醒我们,不管是写脚本或者程序文件是错误报告消息的重要性,不准确的日志消息太有误导性了。
相关文章推荐
- 编译Android源码时常见问题以及解决方法
- android在eclipse中打包(签名包)方法及常见问题解决
- Cocos2dx Cygwin编译-格式问题“CocosDenshion/android/SimpleAudioEngine” make error解决方法
- android adb常见问题的解决方法!
- DEX 方法超过64K限制和gradle编译OOM问题解决,异常名:Error:Execution failed for task ':app:dexDebug'. > com.android.ide
- [Android开发常见问题-11] Unable to execute dex: Multiple dex files define 解决方法
- Android开发环境搭建及常见问题解决方法
- Android Studio 怎么添加使用第三方jar包及无法编译的问题解决方法
- Android常见的几个问题及解决方法
- Android Studio编译出现null value in entry :incrementalFolder问题解决方法
- Android开发常见问题及解决方法
- linux 内核编译:内核配置原理与常见配置问题的解决方法&&内核版本控制解析
- android studio DEX 方法超过64K限制和gradle编译OOM问题解决,异常名:Error:Execution failed for task ':app:dexDebug'. >
- Android开发由eclipse转Android Studio中一些常见出错问题解决方法
- 编译android遇到java虚拟机堆内存不够的问题 java.lang.OutOfMemoryError: GC overhead limit exceeded 解决方法
- Android开发-工具:Android Studio 怎么添加使用第三方jar包及无法编译的问题解决方法
- Android应用程序常见编译问题解决
- Android4.4/CM11编译常见错误及解决方法!
- linux 内核编译:内核配置原理与常见配置问题的解决方法&&内核版本控制解析
- Android studio在使用过程中常见的问题及解决方法(不定期更新),androidstudi