我的环境:
OS: ubuntu 12.10
android-ndk-r7 ffmpeg: 0.8
下面是编译步骤:
第一步:
安装配置ndk
运行ndk-build,如果显示如下信息,则表示安装成功
通过设置宏NDK_PROJECT_PATH来指定工程目录
export NDK_PROJECT_PATH=/home/robin/Desktop/wshare/jni
第二步:下载ffmpeg源码
第三步:
建立文件夹jni,把ffmpeg源码解压至jni目录下,用ndk编译时,jni目录是必须的,否则编译出错。
这一步后目录结构如下:
ndk-build 默认编译jni下的文件,如果它找不到该目录,就要通过设置NDK_PROJECT_PATH来告诉它。
如果当前工作目录是在jni目录下或在jni的直接父目录中,则不需要设置这个宏。
第四步:
在ffmpeg目录下创建config_android.sh文件,内容设置如下。需要根据本机的ndk目录做相应更改。有些参数是必须的,有些参数可以根据应用环境按需设置。
NDK_ROOT=/home/robin/Desktop/android-ndk-r7 PREBUILT=${NDK_ROOT}/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86 PLATFORM=${NDK_ROOT}/platforms/android-14/arch-arm ./configure --target-os=linux \ --arch=arm \ --enable-small \ --enable-static \ --disable-asm \ --enable-armv5te \ --enable-cross-compile \ --disable-debug \ --disable-doc \ --disable-stripping \ --disable-ffmpeg \ --disable-ffplay \ --disable-ffprobe \ --disable-ffserver \ --disable-encoders \ --disable-muxers \ --disable-devices \ --disable-hwaccels \ --disable-bsfs \ --disable-protocols \ --disable-avdevice \ --disable-shared \ --disable-filters \ --disable-postproc \ --cc=$PREBUILT/bin/arm-linux-androideabi-gcc \ --cross-prefix=$PREBUILT/bin/arm-linux-androideabi- \ --nm=$PREBUILT/bin/arm-linux-androideabi-nm \ --extra-cflags="-fPIC -DANDROID" \ --extra-ldflags='-L$PLATFORM/usr/lib -nostdlib' \ echo "#undef restrict" >> config.h echo "#define restrict __restrict__" >> config.h echo "#undef HAVE_LRINT" >> config.h echo "#define HAVE_LRINT 1" >> config.h echo "#undef HAVE_LRINTF" >> config.h echo "#define HAVE_LRINTF 1" >> config.h echo "#undef HAVE_ROUND" >> config.h echo "#define HAVE_ROUND 1" >> config.h echo "#undef HAVE_ROUNDF" >> config.h echo "#define HAVE_ROUNDF 1" >> config.h echo "#undef HAVE_TRUNCF" >> config.h echo "#define HAVE_TRUNCF 1" >> config.h
第五步:
运行./config_android.sh开始进行配置
运行过程中如果出错,可以参看config.log了解具体出错原因,一般而言,出错是由于相关目录没有配置正确。
configure完成后,编辑刚刚生成的config.h,找到这句
#define restrict restrict
Android的GCC不支持restrict关键字,于是修改成下面这样
#define restrict
编辑libavutil/libm.h,把其中的static方法都删除。
可以用
#if 0
…
#endif 注释掉
第六步:
分别修改libavcodec、libavfilter、libavformat、libavutil、libpostproc和libswscale下的Makefile,把每个Makefile中的下面两句删除或注释掉
include $(SUBDIR)../config.mak
include $(SRC_PATH)/subdir.mak
第七步:
在ffmpeg下添加一个文件av.mk,内容如下
# 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))
第八步:
添加一系列的Android.mk,在jni目录下的内如如下:
include $(all-subdir-makefiles)
在ffmpeg目录下,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))
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)
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)
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)
第九步:
运行ndk-build
编译完成后,编译器会在jni相同的目录下创建两个文件夹libs, obj。编译输出会放在这两个文件夹中。
Android.mk中部分宏的说明:
LOCAL_PATH := $(call my-dir)
一个Android.mk 文件首先必须定义好LOCAL_PATH变量。它用于在开发树中查找源文件。在这个例子中,宏函数’my-dir’,
由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录)。
include $( CLEAR_VARS)
CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES,
LOCAL_STATIC_LIBRARIES, 等等...),
除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。
LOCAL_MODULE := hello-jni
编译的目标对象,LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。
注意:编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'hello-jni'的共享库模块,将会生成'libhello-jni.so'文件。
重要注意事项:
如果你把库命名为‘libhello-jni’,编译系统将不会添加任何的lib前缀,也会生成 'libhello-jni.so',这是为了支持来源于Android平台的
源代码的Android.mk文件,如果你确实需要这么做的话。
LOCAL_SRC_FILES := hello-jni.c
LOCAL_SRC_FILES变量必须包含将要编译打包进模块中的C或C++源代码文件。注意,你不用在这里列出头文件和包含文件,因为编
译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。
注意,默认的C++源码文件的扩展名是’.cpp’. 指定一个不同的扩展名也是可能的,只要定义LOCAL_DEFAULT_CPP_EXTENSION变量,
不要忘记开始的小圆点(也就是’.cxx’,而不是’cxx’)
include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY表示编译生成共享库,是编译系统提供的变量,指向一个GNU Makefile脚本,负责收集自从上次调用
'include $(CLEAR_VARS)'以来,定义在LOCAL_XXX变量中的所有信息,并且决定编译什么,如何正确地去做。还有
BUILD_STATIC_LIBRARY变量表示生成静态库:lib$(LOCAL_MODULE).a, BUILD_EXECUTABLE 表示生成可执行文件。
参考:
http://www.cnblogs.com/qq78292959/archive/2011/01/12/2076982.html
http://www.cnblogs.com/hibraincol/archive/2011/05/30/2063847.html