ffmpeg 编译至android

ffmpeg 版本0.65

ndk 版本 5c

  1. 编写 mk 文件
    1. 在 /root/ffmpeg/jni 目录中创建一个 Android.mk 文件,内容如下
      include $(all-subdir-makefiles)
    2. 在 /root/ffmpeg/jni/ffmpeg-0.6.1 目录中创建一个 Android.mk 文件,内容如下
      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))
    3. 在 /root/ffmpeg/jni/ffmpeg-0.6.1 目录中创建一个 av.mk 文件,内容如下
      # 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))
    4. 在 /root/ffmpeg/jni/ffmpeg-0.6.1/libavcodec 目录中创建一个 Android.mk 文件,内容如下
      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)
    5. 在 /root/ffmpeg/jni/ffmpeg-0.6.1/libavformat 目录中创建一个 Android.mk 文件,内容如下
      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)
    6. 在 libavfilter、libavutil、libpostproc 和 libswscale 目录中各创建一个 Android.mk 文件,内容如下
      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)
  2. 修改 libm.h 文件和 Makefile 文件
    1. 编辑 /root/ffmpeg/jni/ffmpeg-0.6.1/libavutil 目录中的 libm.h 文件,删除以下 static 方法
      #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 */
    2. 编辑 libavcodec、libavfilter、libavformat、libavutil、libpostproc 和 libswscale 目录中的 Makefile 文件,删除
      include $(SUBDIR)../subdir.mak
      include $(SUBDIR)../config.mak
  3. 生成 config.h 文件
    1. 在 /root/ffmpeg/jni/ffmpeg-0.6.1 目录中创建一个 config.sh 文件,使用 Android NDK r4b 编译时内容如下
      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"
    2. 打开终端,进入 /root/ffmpeg/jni/ffmpeg-0.6.1 目录,运行下面的命令
      chmod +x config.sh./config.sh
      ffmpeg 编译至android_第1张图片
    3. 编辑 /root/ffmpeg/jni/ffmpeg-0.6.1 目录中的 config.h 文件,将
      #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  的情况还是完全不同的,请继续往下读。

  1. 使用 Android NDK r4b 编译

    打开 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 文件 
    ffmpeg 编译至android_第2张图片

    修改后的 build-binary.mk 文件 

    保存 build-binary.mk 文件之后,运行下面的命令编译

    /root/android-ndk-r4b/ndk-build NDK_PROJECT_PATH=/root/ffmpeg

    接着你会看到 warning 不停的出现在屏幕上,熬过这段心惊肉跳的时间之后,你会看到 libffmpeg.so 文件已经被编译生成了。


    ffmpeg 编译至android_第3张图片

    看看 /root/ffmpeg/obj/local/armeabi 目录中的 libffmpeg.so 文件,文件大小是 12.2MB 

    ffmpeg 编译至android_第4张图片

    再看看 /root/ffmpeg/libs/local/armeabi 目录中的 libffmpeg.so 文件,文件大小是 3.2MB

    ffmpeg 编译至android_第5张图片
  2. 使用 Android NDK r5 编译

    打开 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
     
     
     
     
     
  1. /*
     * 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)
  2. LOCAL_PATH := $(call my-dir)


    include $(CLEAR_VARS)
    LOCAL_MODULE := avcodec
    LOCAL_SRC_FILES := libavcodec.a 
    LOCAL_CFLAGS :=-Ilibavcodec
    LOCAL_EXPORT_C_INCLUDES := libavcodec
    LOCAL_EXPORT_CFLAGS := -Ilibavcodec
    LOCAL_EXPORT_LDLIBS := -llog
    include $(PREBUILT_STATIC_LIBRARY)


    include $(CLEAR_VARS)
    LOCAL_MODULE := avformat
    LOCAL_SRC_FILES := libavformat.a 
    LOCAL_CFLAGS :=-Ilibavformat
    LOCAL_EXPORT_C_INCLUDES := libavformat
    LOCAL_EXPORT_CFLAGS := -Ilibavformat
    LOCAL_EXPORT_LDLIBS := -llog
    include $(PREBUILT_STATIC_LIBRARY)


    include $(CLEAR_VARS)
    LOCAL_MODULE := avutil
    LOCAL_SRC_FILES := libavutil.a 
    LOCAL_CFLAGS :=-Ilibavutil
    LOCAL_EXPORT_C_INCLUDES := libavutil
    LOCAL_EXPORT_CFLAGS := -Ilibavutil
    LOCAL_EXPORT_LDLIBS := -llog


    include $(PREBUILT_STATIC_LIBRARY)




    include $(CLEAR_VARS)
    LOCAL_MODULE := swscale
    LOCAL_SRC_FILES :=libswscale.a 
    LOCAL_CFLAGS :=-Ilibswscale
    LOCAL_EXPORT_C_INCLUDES := libswscale
    LOCAL_EXPORT_CFLAGS := -I$libswscale
    LOCAL_EXPORT_LDLIBS := -llog
    include $(PREBUILT_STATIC_LIBRARY)






    include $(CLEAR_VARS)
    LOCAL_MODULE    := hello-jni
    LOCAL_SRC_FILES := hello-jni.c
    LOCAL_LDLIBS    := -L$(LOCAL_PATH) -lm -lz -lbz2
    LOCAL_STATIC_LIBRARIES := avcodec avformat avutil swscale


    include $(BUILD_SHARED_LIBRARY)


     

你可能感兴趣的:(android,Path,include,float,library,makefile)