FFmpeg Android平台编译与使用

来源:互联网 发布:ubuntu下载qq 编辑:程序博客网 时间:2024/05/17 03:19

FFmepg使用Makefile来编译,在Linux可以直接使用make编译,在Windows可以使用Cygwin的make来编译,FFmpeg可编译出的平台有Linux、Mac OS X、Windows、Android和IOS,只需要替换掉编译工具链和设置与平台相关的属性即可。微软也自己弄了一个项目FFmpegInterop来让FFmpeg支持WindowsPhone平台。

此文参考以下两篇文章

ffmpeg编译android 硬解码支持库 libstagefright

Building FFMPEG for Android on x86

FFmpeg需要额外编译的库

libfaac、libx264、libx265等库需要单独编译,FFmpeg支持他们,但是需要在链接的时候链接这些库。 
最近才发现有一个开源项目AndroidFFmpeg 
写得很好,并且添加了aac、x264,还给出了APP的demo,只需要稍作修改就能编译硬编解码的了。

FFmpeg关键配置文件

  1. config.mak:此配置文件是执行configure时自动生成的,此配置文件定义了编译平台、目标平台、编译工具链、编译器的配置信息、链接器的配置信息、安装目录、库的前缀和后缀名、关键库的版本号及依赖关系、指定需要编译的库和功能(例如要不要把h263编译进去)。此配置文件是根据configure的参数来自动生成的,也就是动态的。
  2. arch.mak:根据CPU架构使用与架构相关的特性、也就是针对特定平台做的优化(一般来说就是汇编优化,arm的neon等)。
  3. common.mak:此配置文件是规定了中间文件、库的编译规则。
  4. library.mak:此配置文件定义了库和相应头文件的安装和卸载规则。

编译工具链

基于android-ndk-r10e制作的GNU-4.8版本的arm、x86版本的交叉编译工具链。

关于如何制作独立的交叉编译工具链可以参考Google的这篇文件:Standalone Toolchain

FFmpeg版本

FFmpeg的版本是2.8,关键库的版本号如下:

libavcodec_VERSION=57.7.100libavdevice_VERSION=57.0.100libavfilter_VERSION=6.12.100libavformat_VERSION=57.8.102libavresample_VERSION=3.0.0libavutil_VERSION=55.4.100libpostproc_VERSION=54.0.100libswresample_VERSION=2.0.100libswscale_VERSION=4.0.100
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

FFmpeg关键库的依赖关系

avcodec_FFLIBS=swresample avutilavdevice_FFLIBS=avformat avcodec swresample avutilavfilter_FFLIBS=swscale avformat avcodec swresample avutilavformat_FFLIBS=avcodec swresample avutilavresample_FFLIBS= avutilavutil_FFLIBS=postproc_FFLIBS= avutilswresample_FFLIBS= avutilswscale_FFLIBS= avutil
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

以下脚本基于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/configureindex 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • libstagefright.cpp中的修改,这个应该说是一个错误了,不应该发生才对的,meta是一个智能指针(sp)
diff --git a/libavcodec/libstagefright.cpp b/libavcodec/libstagefright.cppindex 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; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

关键变量

  1. APP_OUT:定义安装的主目录,最终的安装目录还会根据具体的架构而定。
  2. APP_ABI:定义生成的架构。
  3. APP_DEBUG:定义是否生成debug版本的库。
#------------------------------------------------------------------------# File Name: build_libstagefright# Author: liuliang# Mail: momo0853@live.com# Time: Mon 26 Oct 2015 11:41:34 AM CST#------------------------------------------------------------------------#!/bin/bashAPP_OUT=outAPP_ABI="armeabi-v7a"  # 'armeabi-v7a' 'x86'APP_DEBUG=debug # 'debug' or 'release'ANDROID_SOURCE=Android/android_sourceANDROID_LIBS=Android/android_libsecho "Fetching Android system headers"# this framework platform is 9git clone --depth=1  --branch gingerbread-release https://github.com/CyanogenMod/android_frameworks_base.git $ANDROID_SOURCE/frameworks/basegit clone --depth=1  --branch gingerbread-release https://github.com/CyanogenMod/android_system_core.git     $ANDROID_SOURCE/system/coreecho "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_LIBSfi# Create APP_OUTif  [  !  -d $APP_OUT ];  then    mkdir $APP_OUTfiMY_EXTRA_CFLAGS="-DANDROID"if  [  "debug"  =  "$APP_DEBUG"  ];  then    MY_EXTRA_CFLAGS="$_EXTRA_CFLAGS -DNDEBUG"fifor 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 cleandone
  • 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
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

FFmpeg在Android平台的使用

如果一切编译顺利,那么生成目录应该是这样的

out/├── armeabi-v7a│   ├── bin│   ├── configuration.txt│   ├── include│   ├── info.txt│   ├── lib│   ├── out│   └── share└── x86    ├── bin    ├── configuration.txt    ├── include    ├── info.txt    ├── lib    └── share
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  1. bin目录里面是ffmpeg的demo(ffmpeg ffprobe ffserver)
  2. include里面按照相应的库导出的相应的头文件
  3. lib里面是一个个独立的静态库
  4. 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
  • 1

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)))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

单独编译后应该是这个样子的:

[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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

目前遗留的疑问

由于我早先就基于libstagefright做过Android平台的硬编码,这个是与版本相关的才对,为啥它只需要一个版本的库和头文件呢(platform是10)?这点我很疑惑,vlc同样也用到了libavcodec,但是却有10~21的头文件和库,我早先的做法是参考vlc的思想。

0 0
原创粉丝点击