如何用Android NDK编译FFmpeg

如题所述

 一、安装cygwin、配置ndk和下载ffmpeg源码

  这步就不说了,网上很多教程,再次声明本教程只针对ndk R4这个版本。需要说明的是,本人在cygwin安装路径下的.bash_profile文件中指定的NDK路径如下所示。因为本人装了好几个NDK,因此后面的R4只是个标示。

  NDK_R4=/cygdrive/d/android-ndk-r4
  export NDK_R4

  二、编译前准备和编译

  1、因为R4这个NDK比较旧,交叉编译的时候需要在一个Android环境中,那简单,创建一个Android空项目,把整个项目拷出来,在项目下建立一个文件夹jni,把ffmpeg0.6.6的源码拷进去。左图,HelloJni就是我新建的一个项目,Android.mk这时候你还没有,先不用管。右图ffmpeg-0.6.6文件夹的内容要跟我一样,直接就是代码。我这里的ffmpeg_cywin这个文件夹是随便建的,放哪里无所谓的。

  

  

  2、在ffmpeg-0.6.6下建立一个文件config.sh,内容如下所示。需要注意的是,unix下的换行符和windows下是不一样,如果直接拷贝到windows下的记事本,后面执行这个config.sh的时候会出问题,这里我用的是notepad++编辑的,在编辑->档案格式转换->转换为UNIX格式。(注意,后面的所有的Android.mk的编辑都有此要求)。

  简单说一下这个config.sh,PREBUILT和PLATFORM根据你安装ndk的位置而不同,config.sh其实是一个脚本,执行这个脚本的时候又调用了另外一个脚本configure,configure主要是根据编译选项(下面enable disable那些),生成相应的编译配置,就是说你想要编译ffmpeg什么模块就自己定制编译选项的内容。基本上这个文件只要修改一下PREBUILT和PLATFORM就行,其他都不用改。

  #!/bin/bash
  export PREBUILT=D://android-ndk-r4/build/prebuilt/windows/arm-eabi-4.4.0
  export PLATFORM=D://android-ndk-r4/build/platforms/android-8/arch-arm
  ./configure --target-os=linux \
  --arch=arm \
  --enable-version3 \
  --enable-gpl \
  --enable-nonfree \
  --disable-stripping \
  --disable-ffmpeg \
  --disable-ffplay \
  --disable-ffserver \
  --disable-ffprobe \
  --disable-encoders \
  --disable-muxers \
  --disable-devices \
  --disable-protocols \
  --enable-protocol=file \
  --enable-avfilter \
  --disable-network \
  --disable-mpegaudio-hp \
  --disable-avdevice \
  --enable-cross-compile \
  --cc=$PREBUILT/bin/arm-eabi-gcc \
  --cross-prefix=$PREBUILT/bin/arm-eabi- \
  --nm=$PREBUILT/bin/arm-eabi-nm \
  --extra-cflags="-fPIC -DANDROID" \
  --disable-asm \
  --enable-neon \
  --enable-armv5te \
  --extra-ldflags="-Wl,-T,$PREBUILT/arm-eabi/lib/ldscripts/armelf.x -Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib $PREBUILT/lib/gcc/arm-eabi/4.4.0/crtbegin.o $PREBUILT/lib/gcc/arm-eabi/4.4.0/crtend.o -lc -lm -ldl"
  3、修改configure文件,找到下图的内容,修改成我这样,这个是用来存放执行脚本过程的临时文件的,我这里用的是D://NDK,你可以设置其他地方,但是要先创建好这个文件夹,放哪里无所谓的。

  4、然后在cywin中进入ffmpeg0.6.6文件夹,执行chmod -x config.sh,然后执行./config,此过程需要一定的时间。如果这一步出现问题,很有可能是你config.sh中的PREBUILT和PLATFORM的路径设置不对,或者是你拷贝内容到config.sh的时候没有在UNIX格式下。执行完如下图所示。

  5、在ffmpeg-0.6.6下会生成一个config.h文件,编辑它,找到#define restrict restrict这一行,把它改成#define restrict

  6、在libavutil/libm.h下,把所有static的方法注释掉或者直接删掉。

  7、修改libavcodec,libavfilter,libavformat,libavutil,libpostproc和libswscale目录的MakeFile文件,每个文件中,删除语句

  include $( SUBDIR ) ../config.mak 和 include $ (SUBDIR) .. / subdir.mak。

  libavcodec下的makefile中搜索inverse.o,把它所在的那一行删掉,要不编译的时候会冲突。

  8、在ffmpeg-0.6.6文件夹下,创建av.mk文件(UNIX格式),内容如下:

  #LOCAL_PATH is one of libavutil, libavcodec, libavformat, or libswscale

  #include $(LOCAL_PATH)/../config-$(TARGET_ARCH).mak
  include $(LOCAL_PATH)/../config.mak

  OBJS :=
  OBJS-yes :=
  MMX-OBJS-yes :=
  include $(LOCAL_PATH)/Makefile

  # collect objects
  OBJS-$(HAVE_MMX) += $(MMX-OBJS-yes)
  OBJS += $(OBJS-yes)

  FFNAME := lib$(NAME)
  FFLIBS := $(foreach,NAME,$(FFLIBS),lib$(NAME))
  FFCFLAGS = -DHAVE_AV_CONFIG_H -Wno-sign-compare -Wno-switch -Wno-pointer-sign
  FFCFLAGS += -DTARGET_CONFIG=\"config-$(TARGET_ARCH).h\"

  ALL_S_FILES := $(wildcard $(LOCAL_PATH)/$(TARGET_ARCH)/*.S)
  ALL_S_FILES := $(addprefix $(TARGET_ARCH)/, $(notdir $(ALL_S_FILES)))

  ifneq ($(ALL_S_FILES),)
  ALL_S_OBJS := $(patsubst %.S,%.o,$(ALL_S_FILES))
  C_OBJS := $(filter-out $(ALL_S_OBJS),$(OBJS))
  S_OBJS := $(filter $(ALL_S_OBJS),$(OBJS))
  else
  C_OBJS := $(OBJS)
  S_OBJS :=
  endif

  C_FILES := $(patsubst %.o,%.c,$(C_OBJS))
  S_FILES := $(patsubst %.o,%.S,$(S_OBJS))

  FFFILES := $(sort $(S_FILES)) $(sort $(C_FILES))

  9、在jni文件夹下,创建Android.mk(UNIX格式),内容如下:
  include $(all-subdir-makefiles)

  10、在ffmpeg-0.6.6文件夹下,创建Android.mk,内容如下:
  LOCAL_PATH := $(call my-dir)
  include $(CLEAR_VARS)
  LOCAL_STATIC_LIBRARIES := libavformat libavcodec libavutil libpostproc libswscale
  LOCAL_MODULE := ffmpeg
  include $(BUILD_SHARED_LIBRARY)
  include $(call all-makefiles-under,$(LOCAL_PATH))

  11、在ffmpeg-0.6.6\libavformat下,创建Android.mk,内容如下:
  LOCAL_PATH := $(call my-dir)
  include $(CLEAR_VARS)
  include $(LOCAL_PATH)/../av.mk
  LOCAL_SRC_FILES := $(FFFILES)
  LOCAL_C_INCLUDES := \
  $(LOCAL_PATH) \
  $(LOCAL_PATH)/..
  LOCAL_CFLAGS += $(FFCFLAGS)
  LOCAL_CFLAGS += -include "string.h" -Dipv6mr_interface=ipv6mr_ifindex
  LOCAL_LDLIBS := -lz
  LOCAL_STATIC_LIBRARIES := $(FFLIBS)
  LOCAL_MODULE := $(FFNAME)
  include $(BUILD_STATIC_LIBRARY)

  12、在ffmpeg-0.6.6\libavcodec下,创建Android.mk,内容如下:
  LOCAL_PATH := $(call my-dir)
  include $(CLEAR_VARS)
  include $(LOCAL_PATH)/../av.mk
  LOCAL_SRC_FILES := $(FFFILES)
  LOCAL_C_INCLUDES := \
  $(LOCAL_PATH) \
  $(LOCAL_PATH)/..
  LOCAL_CFLAGS += $(FFCFLAGS)
  LOCAL_LDLIBS := -lz
  LOCAL_STATIC_LIBRARIES := $(FFLIBS)
  LOCAL_MODULE := $(FFNAME)
  include $(BUILD_STATIC_LIBRARY)

  13、在ffmpeg-0.6.6\libavfilter、libavutil、libpostproc和libswscale下,创建Android.mk,内容如下:
  LOCAL_PATH := $(call my-dir)
  include $(CLEAR_VARS)
  include $(LOCAL_PATH)/../av.mk
  LOCAL_SRC_FILES := $(FFFILES)
  LOCAL_C_INCLUDES := \
  $(LOCAL_PATH) \
  $(LOCAL_PATH)/..
  LOCAL_CFLAGS += $(FFCFLAGS)
  LOCAL_STATIC_LIBRARIES := $(FFLIBS)
  LOCAL_MODULE := $(FFNAME)
  include $(BUILD_STATIC_LIBRARY)
  14、然后在jni目录下,运行$NDK_R4/ndk-build -B,这里的命令需要根据你自己的情况修改,然后就开始编译了。过程需要10来分钟,成功之后,会在libs下生产libffmpeg.so。如果编译出来的libffmpeg.so只有1.5k,得如下修改一下NDK,再重新编译。

  把下面红色部分加到NDK的build/core/build-binary.mk里:
  LOCAL_STATIC_LIBRARIES := $(call strip-lib-prefix,$(LOCAL_STATIC_LIBRARIES))
  LOCAL_STATIC_WHOLE_LIBRARIES := $(call strip-lib-prefix,$(LOCAL_STATIC_WHOLE_LIBRARIES))
  ...
  static_libraries := $(call map,static-library-path,$(LOCAL_STATIC_LIBRARIES))
  static_whole_libraries := $(call map,static-library-path,$(LOCAL_STATIC_WHOLE_LIBRARIES))
  ...
  $(call module-add-static-depends,$(LOCAL_MODULE),$(LOCAL_STATIC_LIBRARIES))
  $(call module-add-static-depends,$(LOCAL_MODULE),$(LOCAL_STATIC_WHOLE_LIBRARIES))
  ...
  $(LOCAL_BUILT_MODULE): $(static_libraries) $(static_whole_libraries) $(shared_libraries)
  ...
  $(LOCAL_BUILT_MODULE): PRIVATE_STATIC_LIBRARIES := $(static_libraries)
  $(LOCAL_BUILT_MODULE): PRIVATE_WHOLE_STATIC_LIBRARIES := $(static_whole_libraries)
  接着再将最外层ffmpeg/Android.mk里面的LOCAL_STATIC_LIBRARIES改成LOCAL_STATIC_WHOLE_LIBRARIES
温馨提示:答案为网友推荐,仅供参考