ffmpeg 版本0.65
ndk 版本 5c
include $(all-subdir-makefiles)
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_WHOLE_STATIC_LIBRARIES := libavformat libavcodec libavutil libpostproc libswscaleLOCAL_MODULE := ffmpeginclude $(BUILD_SHARED_LIBRARY)include $(call all-makefiles-under,$(LOCAL_PATH))
# LOCAL_PATH is one of libavutil, libavcodec, libavformat, or libswscale#include $(LOCAL_PATH)/../config-$(TARGET_ARCH).makinclude $(LOCAL_PATH)/../config.makOBJS :=OBJS-yes :=MMX-OBJS-yes :=include $(LOCAL_PATH)/Makefile# collect objectsOBJS-$(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-signFFCFLAGS += -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))elseC_OBJS := $(OBJS)S_OBJS :=endifC_FILES := $(patsubst %.o,%.c,$(C_OBJS))S_FILES := $(patsubst %.o,%.S,$(S_OBJS))FFFILES := $(sort $(S_FILES)) $(sort $(C_FILES))
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)include $(LOCAL_PATH)/../av.mkLOCAL_SRC_FILES := $(FFFILES)LOCAL_C_INCLUDES := \ $(LOCAL_PATH) \ $(LOCAL_PATH)/..LOCAL_CFLAGS += $(FFCFLAGS)LOCAL_LDLIBS := -lzLOCAL_STATIC_LIBRARIES := $(FFLIBS)LOCAL_MODULE := $(FFNAME)include $(BUILD_STATIC_LIBRARY)
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)include $(LOCAL_PATH)/../av.mkLOCAL_SRC_FILES := $(FFFILES)LOCAL_C_INCLUDES := \ $(LOCAL_PATH) \ $(LOCAL_PATH)/..LOCAL_CFLAGS += $(FFCFLAGS)LOCAL_CFLAGS += -include "string.h" -Dipv6mr_interface=ipv6mr_ifindexLOCAL_LDLIBS := -lzLOCAL_STATIC_LIBRARIES := $(FFLIBS)LOCAL_MODULE := $(FFNAME)include $(BUILD_STATIC_LIBRARY)
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)include $(LOCAL_PATH)/../av.mkLOCAL_SRC_FILES := $(FFFILES)LOCAL_C_INCLUDES := \ $(LOCAL_PATH) \ $(LOCAL_PATH)/..LOCAL_CFLAGS += $(FFCFLAGS)LOCAL_STATIC_LIBRARIES := $(FFLIBS)LOCAL_MODULE := $(FFNAME)include $(BUILD_STATIC_LIBRARY)
#if !HAVE_LRINTstatic av_always_inline av_const longint lrint(double x){ return rint(x);}#endif/* HAVE_LRINT */#if !HAVE_LRINTFstatic av_always_inline av_const longint lrintf(float x){ return (int)(rint(x));}#endif/* HAVE_LRINTF */#if !HAVE_ROUNDstatic av_always_inline av_const double round(double x){ return (x > 0) ? floor(x + 0.5) : ceil(x - 0.5);}#endif/* HAVE_ROUND */#if !HAVE_ROUNDFstatic av_always_inline av_const float roundf(float x){ return (x > 0) ? floor(x + 0.5) : ceil(x - 0.5);}#endif/* HAVE_ROUNDF */#if !HAVE_TRUNCFstatic av_always_inline av_const float truncf(float x){ return (x > 0) ? floor(x) : ceil(x);}#endif/* HAVE_TRUNCF */
include $(SUBDIR)../subdir.mak和
include $(SUBDIR)../config.mak
PREBUILT=/root/android-ndk-r4b/build/prebuilt/linux-x86/arm-eabi-4.4.0PLATFORM=/root/android-ndk-r4b/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"使用 Android NDK r5 编译时内容如下
#!/bin/bashPREBUILT=/root/android-ndk-r5/toolchains/arm-eabi-4.4.0/prebuilt/linux-x86PLATFORM=/root/android-ndk-r5/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"
chmod +x config.sh./config.sh
#define restrict restrict
修改为 #define restrict
四、开始编译 FFmpeg
很多人在用 havlenapetr 的方法编译 FFmpeg 时只得到一个 1599 字节 1.6KB 大小的 libffmpeg.so 文件,无论是用 Android NDK r4b 编译还是用 Android NDK r5 编译结果都是如此,很让人抓狂。我也很郁闷,最后花时间研究了一下 NDK,终于发现了解决方法,而且 Android NDK r4b 和 Android NDK r5 的情况还是完全不同的,请继续往下读。
打开 android-ndk-r4b/build/toolchains/arm-eabi-4.4.0 目录中的 setup.mk 文件,你会发现 Google 在里面定义了一个用于编译动态库的 cmd-build-shared-library 函数。在cmd-build-shared-library 函数中 Google 使用了 PRIVATE_WHOLE_STATIC_LIBRARIES 函数。但是你在 android-ndk-r4b/build/core 目录中的 build-binary.mk 文件里却找不到 PRIVATE_WHOLE_STATIC_LIBRARIES 函数…… 外?WHY?终于搞清楚了,原来得不到正确的 libffmpeg.so 文件不是我的错,而是 Android NDK r4b 的 BUG!你妹啊!你大爷啊!坑爹呢这是!发布前不做测试吗!居然漏掉一个函数!!!(我敢说这是个 BUG 是因为 Google 在 Android NDK r5 中修复了这个 BUG)
木办法,只好手动替 Google 修补这个 BUG。好在修改方法很简单,只需要照 build-binary.mk 文件里的 PRIVATE_STATIC_LIBRARIES 增加一个 PRIVATE_WHOLE_STATIC_LIBRARIES 就行了。具体方法见下图
修改后的 build-binary.mk 文件
保存 build-binary.mk 文件之后,运行下面的命令编译
/root/android-ndk-r4b/ndk-build NDK_PROJECT_PATH=/root/ffmpeg
接着你会看到 warning 不停的出现在屏幕上,熬过这段心惊肉跳的时间之后,你会看到 libffmpeg.so 文件已经被编译生成了。
看看 /root/ffmpeg/obj/local/armeabi 目录中的 libffmpeg.so 文件,文件大小是 12.2MB
再看看 /root/ffmpeg/libs/local/armeabi 目录中的 libffmpeg.so 文件,文件大小是 3.2MB
打开 android-ndk-r5/build/core 目录中的 build-binary.mk 文件,发现 Google 这次没有忘记 PRIVATE_WHOLE_STATIC_LIBRARIES,但还最后编译得到的 libffmpeg.so 文件大小还是不正确。 这次的问题是,android-ndk-r5 默认是使用 arm-linux-androideabi-4.4.3 编译,而不是 arm-eabi-4.4.0。但 android-ndk-r5/toolchains/arm-linux-androideabi-4.4.3 目录中的 setup.mk 文件里定义的 cmd-build-shared-library 函数并没有将静态库文件链接在一起生成动态库文件。所以解决的办法就是在执行 ndk-build 时加上 NDK_TOOLCHAIN 参数,指定使用 arm-eabi-4.4.0 来编译。完整命令如下
/root/android-ndk-r5/ndk-build NDK_PROJECT_PATH=/root/ffmpeg NDK_TOOLCHAIN=arm-eabi-4.4.0 NDK_PLATFORM=android-8
/* * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * Replacements for frequently missing libm functions */ #ifndef AVUTIL_LIBM_H #define AVUTIL_LIBM_H #include <math.h> #include "config.h" #include "attributes.h" #if !HAVE_EXP2 #undef exp2 #define exp2(x) exp((x) * 0.693147180559945) #endif /* HAVE_EXP2 */ #if !HAVE_EXP2F #undef exp2f #define exp2f(x) ((float)exp2(x)) #endif /* HAVE_EXP2F */ #if !HAVE_LLRINT #undef llrint #define llrint(x) ((long long)rint(x)) #endif /* HAVE_LLRINT */ #if !HAVE_LLRINTF #undef llrintf #define llrintf(x) ((long long)rint(x)) #endif /* HAVE_LLRINT */ #if !HAVE_LOG2 #undef log2 #define log2(x) (log(x) * 1.44269504088896340736) #endif /* HAVE_LOG2 */ #if !HAVE_LOG2F #undef log2f #define log2f(x) ((float)log2(x)) #endif /* HAVE_LOG2F */ #if !HAVE_LRINT #undef lrint #define lrint(x) ((long int)(rint((double)x))) #endif /* HAVE_LRINT */ #if !HAVE_LRINTF #undef lrintf #define lrintf(x) ((long int)(rint((float)x))) #endif /* HAVE_LRINTF */ #if !HAVE_ROUND #undef round #define round(x) ((double)(((double)x > 0) ? floor((double)x + 0.5) : ceil((double)x - 0.5))) #endif /* HAVE_ROUND */ #if !HAVE_ROUNDF #undef roundf #define roundf(x) ((float)(((float)x > 0) ? floor((float)x + 0.5) : ceil((float)x - 0.5))) #endif /* HAVE_ROUNDF */ #if !HAVE_TRUNCF #undef truncf #define truncf(x) ((float)(((float)x > 0) ? floor((float)x) : ceil((float)x))) #endif /* HAVE_TRUNCF */ #endif /* AVUTIL_LIBM_H */
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := LIB1 LOCAL_SRC_FILES := libavcodec.a include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := LIB2 LOCAL_SRC_FILES := libavformat.a include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := LIB3 LOCAL_SRC_FILES := libavutil.a include $(PREBUILT_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := hello-jni LOCAL_SRC_FILES := hello-jni.c LOCAL_STATIC_LIBRARIES := LIB1 LIB2 LIB3 include $(BUILD_SHARED_LIBRARY)