FFmpeg Android平台编译与使用
2015-10-26 22:55
477 查看
FFmepg使用Makefile来编译,在Linux可以直接使用make编译,在Windows可以使用Cygwin的make来编译,FFmpeg可编译出的平台有Linux、Mac OS X、Windows、Android和IOS,只需要替换掉编译工具链和设置与平台相关的属性即可。微软也自己弄了一个项目FFmpegInterop来让FFmpeg支持WindowsPhone平台。
Building FFMPEG for Android on x86
最近才发现有一个开源项目AndroidFFmpeg
写得很好,并且添加了aac、x264,还给出了APP的demo,只需要稍作修改就能编译硬编解码的了。
arch.mak:根据CPU架构使用与架构相关的特性、也就是针对特定平台做的优化(一般来说就是汇编优化,arm的neon等)。
common.mak:此配置文件是规定了中间文件、库的编译规则。
library.mak:此配置文件定义了库和相应头文件的安装和卸载规则。
关于如何制作独立的交叉编译工具链可以参考Google的这篇文件:Standalone Toolchain
以下脚本基于ffmpeg/tools/build_libstagefright改写而成。由于所依赖的库update-cm-7.0.3-N1-signed.zip的链接无效了,所以采用我自己弄的一套库。由于github的访问速度较慢,我就采用了csdn的git管理。由于对它里面依赖的头文件还没有全部理清,所以暂时还不敢动它的东西。目前仅仅支持Android的armeabi-v7a和x86,如果需要支持其他架构或者平台做类似的我的修改即可。
libstagefright.cpp中的修改,这个应该说是一个错误了,不应该发生才对的,meta是一个智能指针(sp)
APP_ABI:定义生成的架构。
APP_DEBUG:定义是否生成debug版本的库。
bin目录里面是ffmpeg的demo(
include里面按照相应的库导出的相应的头文件
lib里面是一个个独立的静态库
share里面是man和ffmpeg的测试代码,可以利用这些测试demo来理一理这些库的使用方式
有些同学喜欢使用动态库,把这几个静态库编译为动态库即可。我个人比较喜欢静态库,好处有
1. 把用到的静态库全部打到我的动态库中,减少库的个数。
2. 只打包用到的库,精简库的大小,关于库的依赖关系往前看。
这里以armeabi-v7a为例,把Android.mk放在与lib目录同一路径,应该是这个样子的:
Android.mk的内容如下,然后在其他地方使用就直接使用库名来代替,添加在LOCAL_STATIC_LIBRARIES,已经把对应库的头文件export出来了,所以不需要单独添加对应库的头文件路径,这些都是Android NDK的基础知识了。
单独编译后应该是这个样子的:
此文参考以下两篇文章
ffmpeg编译android 硬解码支持库 libstagefrightBuilding FFMPEG for Android on x86
FFmpeg需要额外编译的库
libfaac、libx264、libx265等库需要单独编译,FFmpeg支持他们,但是需要在链接的时候链接这些库。最近才发现有一个开源项目AndroidFFmpeg
写得很好,并且添加了aac、x264,还给出了APP的demo,只需要稍作修改就能编译硬编解码的了。
FFmpeg关键配置文件
config.mak:此配置文件是执行configure时自动生成的,此配置文件定义了编译平台、目标平台、编译工具链、编译器的配置信息、链接器的配置信息、安装目录、库的前缀和后缀名、关键库的版本号及依赖关系、指定需要编译的库和功能(例如要不要把h263编译进去)。此配置文件是根据configure的参数来自动生成的,也就是动态的。arch.mak:根据CPU架构使用与架构相关的特性、也就是针对特定平台做的优化(一般来说就是汇编优化,arm的neon等)。
common.mak:此配置文件是规定了中间文件、库的编译规则。
library.mak:此配置文件定义了库和相应头文件的安装和卸载规则。
编译工具链
基于android-ndk-r10e制作的GNU-4.8版本的arm、x86版本的交叉编译工具链。关于如何制作独立的交叉编译工具链可以参考Google的这篇文件:Standalone Toolchain
FFmpeg版本
FFmpeg的版本是2.8,关键库的版本号如下:libavcodec_VERSION=57.7.100 libavdevice_VERSION=57.0.100 libavfilter_VERSION=6.12.100 libavformat_VERSION=57.8.102 libavresample_VERSION=3.0.0 libavutil_VERSION=55.4.100 libpostproc_VERSION=54.0.100 libswresample_VERSION=2.0.100 libswscale_VERSION=4.0.100
FFmpeg关键库的依赖关系
avcodec_FFLIBS=swresample avutil avdevice_FFLIBS=avformat avcodec swresample avutil avfilter_FFLIBS=swscale avformat avcodec swresample avutil avformat_FFLIBS=avcodec swresample avutil avresample_FFLIBS= avutil avutil_FFLIBS= postproc_FFLIBS= avutil swresample_FFLIBS= avutil swscale_FFLIBS= avutil
以下脚本基于ffmpeg/tools/build_libstagefright改写而成。由于所依赖的库update-cm-7.0.3-N1-signed.zip的链接无效了,所以采用我自己弄的一套库。由于github的访问速度较慢,我就采用了csdn的git管理。由于对它里面依赖的头文件还没有全部理清,所以暂时还不敢动它的东西。目前仅仅支持Android的armeabi-v7a和x86,如果需要支持其他架构或者平台做类似的我的修改即可。
使用方式
把此脚本保存为文件、然后放入ffmpeg/tools中,然后添加执行权限(chmod +x fileName),在ffmpeg位置执行此脚本即可。如果不能同时编译两个ARCH,那么就一个个来吧。必要修改
configure中的修改,参考前辈做法,我至今还未知道为啥需要这样修改。diff --git a/configure b/configure index 1bbaf7f..6ad3f79 100755 --- a/configure +++ b/configure @@ -5369,7 +5369,7 @@ enabled libsnappy && require snappy snappy-c.h snappy_compress -lsnappy enabled libsoxr && require libsoxr soxr.h soxr_create -lsoxr && LIBSOXR="-lsoxr" enabled libssh && require_pkg_config libssh libssh/sftp.h sftp_init enabled libspeex && require_pkg_config speex speex/speex.h speex_decoder_init -lspeex -enabled libstagefright_h264 && require_cpp libstagefright_h264 "binder/ProcessState.h media/stagefright/MetaData.h +enabled libstagefright && require_cpp libstagefright_h264 "binder/ProcessState.h media/stagefright/MetaData.h
libstagefright.cpp中的修改,这个应该说是一个错误了,不应该发生才对的,meta是一个智能指针(sp)
diff --git a/libavcodec/libstagefright.cpp b/libavcodec/libstagefright.cpp index 07cac33..3e5e41c 100644 --- a/libavcodec/libstagefright.cpp +++ b/libavcodec/libstagefright.cpp @@ -280,7 +280,7 @@ static av_cold int Stagefright_init(AVCodecContext *avctx) memcpy(s->orig_extradata, avctx->extradata, avctx->extradata_size); meta = new MetaData; - if (!meta) { + if (!meta.get()) { ret = AVERROR(ENOMEM); goto fail; }
关键变量
APP_OUT:定义安装的主目录,最终的安装目录还会根据具体的架构而定。APP_ABI:定义生成的架构。
APP_DEBUG:定义是否生成debug版本的库。
#------------------------------------------------------------------------ # File Name: build_libstagefright # Author: liuliang # Mail: momo0853@live.com # Time: Mon 26 Oct 2015 11:41:34 AM CST #------------------------------------------------------------------------ #!/bin/bash APP_OUT=out APP_ABI="armeabi-v7a" # 'armeabi-v7a' 'x86' APP_DEBUG=debug # 'debug' or 'release' ANDROID_SOURCE=Android/android_source ANDROID_LIBS=Android/android_libs echo "Fetching Android system headers" # this framework platform is 9 git clone --depth=1 --branch gingerbread-release https://github.com/CyanogenMod/android_frameworks_base.git $ANDROID_SOURCE/frameworks/base git clone --depth=1 --branch gingerbread-release https://github.com/CyanogenMod/android_system_core.git $ANDROID_SOURCE/system/core echo "Fetching Android libraries for linking" # Libraries from any froyo/gingerbread device/emulator should work # fine, since the symbols used should be available on most of them. if [ ! -d "$ANDROID_LIBS" ]; then git clone git://code.csdn.net/momo0853/android-libs.git $ANDROID_LIBS fi # Create APP_OUT if [ ! -d $APP_OUT ]; then mkdir $APP_OUT fi MY_EXTRA_CFLAGS="-DANDROID" if [ "debug" = "$APP_DEBUG" ]; then MY_EXTRA_CFLAGS="$_EXTRA_CFLAGS -DNDEBUG" fi for abi in $APP_ABI; do echo "configure $abi" # Expand the prebuilt/* path into the correct one if [ "$abi" = "x86" ]; then TOOLCHAIN=echo /home/liuliang/soft/my/android_x86 FLAGS="--target-os=linux --cross-prefix=i686-linux-android- --arch=x86 --cpu=i686" EXTRA_CFLAGS="-fpic -pipe -march=atom -msse3 -ffast-math -mfpmath=sse" elif [ "$abi" = "armeabi-v7a" ]; then TOOLCHAIN=echo /home/liuliang/soft/my/android_arm FLAGS="--target-os=linux --cross-prefix=arm-linux-androideabi- --arch=arm --cpu=armv7-a" EXTRA_CFLAGS="-march=armv7-a -mfloat-abi=softfp -mfpu=neon" fi export PATH=$TOOLCHAIN/bin:$PATH ANDROID_LIBS="$ANDROID_LIBS/$abi" FLAGS="$FLAGS --disable-avdevice --disable-decoder=h264 --disable-decoder=h264_vdpau --enable-libstagefright-h264" DEST="$APP_OUT/$abi" FLAGS="$FLAGS --prefix=$DEST" mkdir -p $DEST EXTRA_CFLAGS="$EXTRA_CFLAGS -I$ANDROID_SOURCE/frameworks/base/include -I$ANDROID_SOURCE/system/core/include" EXTRA_CFLAGS="$EXTRA_CFLAGS -I$ANDROID_SOURCE/frameworks/base/media/libstagefright" EXTRA_CFLAGS="$EXTRA_CFLAGS -I$ANDROID_SOURCE/frameworks/base/include/media/stagefright/openmax" EXTRA_CFLAGS="$EXTRA_CFLAGS $MY_EXTRA_CFLAGS" EXTRA_LDFLAGS="-Wl,--fix-cortex-a8 -L$ANDROID_LIBS -Wl,-rpath-link,$ANDROID_LIBS -lstagefright -lstagefright_foundation -lstdc++ -lutils -lbinder -lgnustl_shared" EXTRA_CXXFLAGS="-Wno-multichar -fno-exceptions -fno-rtti" echo $FLAGS --extra-cflags="$EXTRA_CFLAGS" --extra-ldflags="$EXTRA_LDFLAGS" --extra-cxxflags="$EXTRA_CXXFLAGS" > $DEST/info.txt ./configure $FLAGS --extra-cflags="$EXTRA_CFLAGS" --extra-ldflags="$EXTRA_LDFLAGS" --extra-cxxflags="$EXTRA_CXXFLAGS" | tee $DEST/configuration.txt [ $PIPESTATUS == 0 ] || exit 1 make clean make -j64 || exit 1 make install make clean done
FFmpeg在Android平台的使用
如果一切编译顺利,那么生成目录应该是这样的out/ ├── armeabi-v7a │ ├── bin │ ├── configuration.txt │ ├── include │ ├── info.txt │ ├── lib │ ├── out │ └── share └── x86 ├── bin ├── configuration.txt ├── include ├── info.txt ├── lib └── share
bin目录里面是ffmpeg的demo(
ffmpeg
ffprobe
ffserver)
include里面按照相应的库导出的相应的头文件
lib里面是一个个独立的静态库
share里面是man和ffmpeg的测试代码,可以利用这些测试demo来理一理这些库的使用方式
有些同学喜欢使用动态库,把这几个静态库编译为动态库即可。我个人比较喜欢静态库,好处有
1. 把用到的静态库全部打到我的动态库中,减少库的个数。
2. 只打包用到的库,精简库的大小,关于库的依赖关系往前看。
使用方式:
有了这些库和头文件以后我们就可以独立于ffmpeg开发了,以后要更新ffmpeg仅仅需要更新这些头文件和对应的库即可。这里以armeabi-v7a为例,把Android.mk放在与lib目录同一路径,应该是这个样子的:
Android.mk Application.mk bin configuration.txt include info.txt lib out share
Android.mk的内容如下,然后在其他地方使用就直接使用库名来代替,添加在LOCAL_STATIC_LIBRARIES,已经把对应库的头文件export出来了,所以不需要单独添加对应库的头文件路径,这些都是Android NDK的基础知识了。
LOCAL_PATH := $(call my-dir) LIB_STATIC_LIBS := $(wildcard $(LOCAL_PATH)/lib/*.a) $(foreach lib, $(LIB_STATIC_LIBS), \ $(eval include $$(CLEAR_VARS)) \ $(eval LOCAL_MODULE := $(basename $(notdir $(lib)))) \ $(eval LOCAL_SRC_FILES := $(lib)) \ $(eval LOCAL_EXPORT_C_INCLUDE := include/$(basename $(lib))) \ $(eval include $$(PREBUILT_STATIC_LIBRARY)))
单独编译后应该是这个样子的:
[armeabi-v7a] Install : libavcodec.a => out/libs/armeabi-v7a/libavcodec.a [armeabi-v7a] Install : libavfilter.a => out/libs/armeabi-v7a/libavfilter.a [armeabi-v7a] Install : libavformat.a => out/libs/armeabi-v7a/libavformat.a [armeabi-v7a] Install : libavutil.a => out/libs/armeabi-v7a/libavutil.a [armeabi-v7a] Install : libswresample.a => out/libs/armeabi-v7a/libswresample.a [armeabi-v7a] Install : libswscale.a => out/libs/armeabi-v7a/libswscale.a
目前遗留的疑问
由于我早先就基于libstagefright做过Android平台的硬编码,这个是与版本相关的才对,为啥它只需要一个版本的库和头文件呢(platform是10)?这点我很疑惑,vlc同样也用到了libavcodec,但是却有10~21的头文件和库,我早先的做法是参考vlc的思想。相关文章推荐
- Android编程宝典-第二章-Activity
- Android Fragment 真正的完全解析
- Android_10_java调用C(借助NDK工具自动生成.so)
- androidGMS认证之Camera support cross profile image capture
- Android SurfaceFlinger and its' client
- Android权限声明
- 安卓第一次实验解析
- Android中Bitmap,byte[],Drawable,InputStream相互转化工具类
- Android ffmpeg+librtmp+speex交叉编译
- Android_10_javah命令
- Android控件之RadioGroup、RadioButton
- 我的Android进阶之旅------>android中service的onStartCommand()方法中intent为null的问题
- android消息推送
- Android上面通过URL来启动本地应用
- android studio使用发布者证书调试
- Android中measure过程、view绘制原理和MeasureSpec介绍及使用详解
- 【FastDev4Android框架开发】Android崩溃异常捕捉CustomCrash,提升用户体验(五)
- Android获取控件大小的方法
- [Android应用开发] 05.广播和服务
- 安卓开发技术:监听软键盘的显示与隐藏