我的環境:
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