ubuntu_16.04_LTS使用NDK编译FFMPEG_3.1.1
2016-07-29 16:30
453 查看
之前写过 * ubuntu_14.04_LTS使用NDK编译FFMPEG_2.7.2 *的博客。这篇跟上篇类似,不过环境跟FFMPEG版本不同。大部分步骤是一样的,只有几个地方编译时会有BUG。这篇文章的第23步做了详细说明。
1.编译环境
2.NDK安装及配置。
下载NDK
官网下载页:http://developer.android.com/tools/sdk/ndk/index.html
下载后解压。如果是.bin文件直接运行.bin。如果是压缩包解压就行。安装方法网上很多,不会去搜一下。
本人的目录为:
配置NDK环境参数
打开 ~/.bashrc文件:
检查是否安装成功。
3.去官网下载FFMPEG源码
ffmpeg官网:http://ffmpeg.org/
ffmpeg更新很频繁,版本很多。不同版本之间不光修改了api参数,连名字都改了。网上有很多关于NDK编译ffmpeg的文档,但都是比较老的版本。不同版本编译可能会有不同的问题。本人之前根据网上的ffmpeg_0.11.3的编译资料编译了ffmpeg_0.11.5,编译成功,生成了so库。本人打算学习FFMPEG,于是下载了目前官网最新版本(FFMPEG-3.1.1),开始编译。
4.创建jni目录。
因NDK编译默认是该路径,我 的目录是
5.创建Android.mk, 和Application.mk文件
NDK编译需要, 配置android.
11264
mk及配置文件如下。
在jni目录下创建Android.mk,内容如下:
jni下创建Application.mk,内容如下:
6.创建preconfig.sh文件
在ffmpeg_3.1.1目录下创建preconfig.sh文件。名字可自定义,但必须是sh文件,内容如下:
其中PREBUILT,PLATFORM,及–extra-ldflags 后面的路径需要根据你自己NDK的目录来写。现在的配置是根据我的目录来的。
7.创建Android.mk
ffmpeg_3.1.1目录下创建Android.mk文件。内容如下:
8.给preconfig.sh增加执行权限
开始配置:
若无意外,会配置成功,结尾的地方会有一个warning,可忽略。若有错如c compile test failed 或者 交叉编译不能生成可执行文件,说明配置出错,可能是你的NDK路径不对。上面的配置文件在运行时也可能出错,说某个命令找不到,或者有分隔等。这个应该是网页编辑的是自动添加的空格或空行,可手动删除。然后再运行配置文件。
9.生成config.h文件
执行precofnig.sh之后会在ffmpeg_3.1.1目录生成config.h文件,增加权限
然后打开编辑改文件,找到
改成
因不能识别restric指令。
找到
屏蔽掉,这句在编译时会报错,重定义。然后保存。
10.屏蔽libm.h里面的静态函数
然后找到libavutil/libm.h文件,打开将里面的static函数全部屏蔽掉,或者用#if 0 关闭,然后保存文件。因后面编译会报错。
11.在libavcodec 目录下创建Android.mk文件,内容如下:
12.在libavfilter目录下创建Android.mk文件,内容如下:
13.在libavformat目录下创建Android.mk文件,内容如下:
14.在libavutil目录下创建Android.mk文件,内容如下:
15.在libpostproc目录下创建Android.mk文件,内容如下:
16.在libswresample目录下创建Android.mk文件,内容如下:
17.在libswscale目录下创建Android.mk文件,内容如下:
18.注释掉包含的config.mak文件
分别将
这句屏蔽掉。
19.重命名libavutil目录下的time.h, time.c文件
把ffmpeg_3.1.1/libavutil/time.h 文件重命名为avtime.h,把ffmpeg_3.1.1/libavutil/time.c重命名为avtime.c。因该文件与NDK里面的time.h同名,引用时会冲突。导致编译出错。然后将引用该头文件的地方 改成 #include “libavutil/avtime.h” 需要修改的文件如下:
可能还会有其他引用 #include “libavutil/time.h”的文件, 编译时若报错,找不到该文件,再更改成
最重要的一点,要在ffmpeg_3.1.1/libavutil/ 目录下的 Makefile文件中,找到time.o的地方改成avtime.o 不然找不到该目标文件。我的文件在131行。找到time.o改成avtime.o。
20.将static的函数(gmtime_r, localtime_r)屏蔽掉
在
21.生成ffversion.h头文件
最后一点,在ffmpeg_3.1.1/libavutil/utils.c 文件中会有
这句。但是在libavutil 目录下并找不到该头文件,编译时会报错。该头文件应该只是个声明啥的,可以自己写。我是用linux 交叉编译工具编译另外一个目录下的ffmpeg_3.1.1之后,在该目录生成了ffversion.h文件,将该文件拷贝到jni/ffmpeg_3.1.1/libavutil/目录下。
ffversion.h头文件很简单,就一个宏,可自动创建,内容如下:
22.在ffmpeg下添加一个文件av.mk,内容如下
23.修改几个代码中的BUG
1. 将 libavcodec/movtextdec.c 文件中的第487行代码
改为:
2.将 libavcodec/proresdec2.c 文件第597 行代码
改为
因为C语音不支持在代码循环中定义变量。
24.准备工作完成,开始编译。
25.等待编译
等待大概十多分钟即可编译完成,编译完成后,会自动在jni上一级目录(本人的是/home/sk/local)生成libs 和obj文件夹。libs下面会有armeabi-v7a/libffmpeg.so 库文件,可以看下大小,编译出来大概是7.7M。结果如下:
到此所有工作已完成,可以开始编写jni在android上使用了。
写点东西不容易,请大家遵守原创。转载引用时请注明出处,谢谢!
借鉴文档:
http://www.cppblog.com/mikesheng/articles/203597.html
1.编译环境
OS: ubuntu_16.04LTS NDK: android_ndk_r9d FFMPEG: ffmpeg_3.1.1
2.NDK安装及配置。
下载NDK
官网下载页:http://developer.android.com/tools/sdk/ndk/index.html
下载后解压。如果是.bin文件直接运行.bin。如果是压缩包解压就行。安装方法网上很多,不会去搜一下。
本人的目录为:
/home/sk/sk/android-ndk-r9d
配置NDK环境参数
打开 ~/.bashrc文件:
export NDK_HOME=/root/android-ndk-r9d export PATH=$PATH:$NDK_HOME 具体根据自己的目录来写(参考:若安装的r8的NDK则为): export NDK_HOME=/root/android-ndk-r8
检查是否安装成功。
$NDK_HOME ndk-build -v
3.去官网下载FFMPEG源码
ffmpeg官网:http://ffmpeg.org/
ffmpeg更新很频繁,版本很多。不同版本之间不光修改了api参数,连名字都改了。网上有很多关于NDK编译ffmpeg的文档,但都是比较老的版本。不同版本编译可能会有不同的问题。本人之前根据网上的ffmpeg_0.11.3的编译资料编译了ffmpeg_0.11.5,编译成功,生成了so库。本人打算学习FFMPEG,于是下载了目前官网最新版本(FFMPEG-3.1.1),开始编译。
4.创建jni目录。
因NDK编译默认是该路径,我 的目录是
/home/sk/local/jni,将解压后的ffmpeg_3.1.1拷贝到jni下,我的是
/home/sk/local/jni/ffmpeg_3.1.1
5.创建Android.mk, 和Application.mk文件
NDK编译需要, 配置android.
11264
mk及配置文件如下。
在jni目录下创建Android.mk,内容如下:
include $(all-subdir-makefiles)
jni下创建Application.mk,内容如下:
# Build both ARMv5TE and ARMv7-A machine code. APP_PLATFORM = android-19 APP_ABI := armeabi-v7a #APP_ABI := $(ARM_ARCH) #Sam modify it to release APP_OPTIM := release #APP_OPTIM := debug #APP_OPTIM = $(MY_OPTIM) APP_CPPFLAGS += -fexceptions APP_CPPFLAGS += -frtti #sam modify it from gnustl_static to gnustl_shared #APP_STL := gnustl_static #APP_STL := gnustl_shared APP_STL := gnustl_shared #APP_CPPFLAGS += -fno-rtti APP_CPPFLAGS += -Dlinux -fsigned-char APP_CFLAGS += -fsigned-char #APP_CPPFLAGS += $(MY_CPPFLAGS) -Dlinux #STLPORT_FORCE_REBUILD := true
6.创建preconfig.sh文件
在ffmpeg_3.1.1目录下创建preconfig.sh文件。名字可自定义,但必须是sh文件,内容如下:
#!/bin/bash PREBUILT=/home/sk/sk/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64 PLATFORM=/home/sk/sk/android-ndk-r9d/platforms/android-19/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-avdevice \ --disable-asm \ --enable-cross-compile \ --cc=$PREBUILT/bin/arm-linux-androideabi-gcc \ --cross-prefix=$PREBUILT/bin/arm-linux-androideabi- \ --strip=$PREBUILT/bin/arm-linux-androideabi-strip \ --extra-cflags="-fPIC -DANDROID" \ --extra-ldflags="-Wl,-T,$PREBUILT/arm-linux-androideabi/lib/ldscripts/armelf_linux_eabi.x -Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib $PREBUILT/lib/gcc/arm-linux-androideabi/4.6/crtbegin.o $PREBUILT/lib/gcc/arm-linux-androideabi/4.6/crtend.o -lc -lm -ldl"
其中PREBUILT,PLATFORM,及–extra-ldflags 后面的路径需要根据你自己NDK的目录来写。现在的配置是根据我的目录来的。
7.创建Android.mk
ffmpeg_3.1.1目录下创建Android.mk文件。内容如下:
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_WHOLE_STATIC_LIBRARIES := libavformat libavcodec libavutil libpostproc libswscale libswresample libavfilter LOCAL_MODULE := ffmpeg include $(BUILD_SHARED_LIBRARY) include $(call all-makefiles-under,$(LOCAL_PATH))
8.给preconfig.sh增加执行权限
chmod a+x preconfig.sh
开始配置:
./preconfig.sh
若无意外,会配置成功,结尾的地方会有一个warning,可忽略。若有错如c compile test failed 或者 交叉编译不能生成可执行文件,说明配置出错,可能是你的NDK路径不对。上面的配置文件在运行时也可能出错,说某个命令找不到,或者有分隔等。这个应该是网页编辑的是自动添加的空格或空行,可手动删除。然后再运行配置文件。
9.生成config.h文件
执行precofnig.sh之后会在ffmpeg_3.1.1目录生成config.h文件,增加权限
chmod a+x config.h
然后打开编辑改文件,找到
#define restrict restrict 或者 #define av_restrict av_restrict
改成
#define restrict 或者 #define av_restrict
因不能识别restric指令。
找到
#define getenv(x) NULL
屏蔽掉,这句在编译时会报错,重定义。然后保存。
10.屏蔽libm.h里面的静态函数
然后找到libavutil/libm.h文件,打开将里面的static函数全部屏蔽掉,或者用#if 0 关闭,然后保存文件。因后面编译会报错。
11.在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)
12.在libavfilter目录下创建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)
13.在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)
14.在libavutil目录下创建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)
15.在libpostproc目录下创建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)
16.在libswresample目录下创建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)
17.在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)
18.注释掉包含的config.mak文件
分别将
libavcodec, libavfilter, libavformat, libavutil, libpostproc, libswresample, libswscale目录下的Makefile文件里面的
#include $(SUBDIR)../config.mak
这句屏蔽掉。
19.重命名libavutil目录下的time.h, time.c文件
把ffmpeg_3.1.1/libavutil/time.h 文件重命名为avtime.h,把ffmpeg_3.1.1/libavutil/time.c重命名为avtime.c。因该文件与NDK里面的time.h同名,引用时会冲突。导致编译出错。然后将引用该头文件的地方 改成 #include “libavutil/avtime.h” 需要修改的文件如下:
ffmpeg/libavformat/avio.c ffmpeg/libavformat/hls.c ffmpeg/libavformat/mux.c ffmpeg/libavformat/utils.c ffmpeg/libavutil/time.c ffmpeg/libavfilter/avf_showcqt.c ffmpeg/libavfilter/setpts.c ffmpeg/libavfilter/f_bench.c ffmpeg/libavfilter/f_realtime.c
可能还会有其他引用 #include “libavutil/time.h”的文件, 编译时若报错,找不到该文件,再更改成
#include "libavutil/avtime.h"
最重要的一点,要在ffmpeg_3.1.1/libavutil/ 目录下的 Makefile文件中,找到time.o的地方改成avtime.o 不然找不到该目标文件。我的文件在131行。找到time.o改成avtime.o。
20.将static的函数(gmtime_r, localtime_r)屏蔽掉
在
ffmpeg_3.1.1/libavutil/time_interval.h文件中,将static的函数(gmtime_r, localtime_r)屏蔽掉。这两个函数也会冲突。
#if 0 #if !HAVE_GMTIME_R && !defined(gmtime_r) static inline struct tm *gmtime_r(const time_t* clock, struct tm *result) { struct tm *ptr = gmtime(clock); if (!ptr) return NULL; *result = *ptr; return result; } #endif #if !HAVE_LOCALTIME_R && !defined(localtime_r) static inline struct tm *localtime_r(const time_t* clock, struct tm *result) { struct tm *ptr = localtime(clock); if (!ptr) return NULL; *result = *ptr; return result; } #endif #endif
21.生成ffversion.h头文件
最后一点,在ffmpeg_3.1.1/libavutil/utils.c 文件中会有
#include "libavutil/ffversion.h"
这句。但是在libavutil 目录下并找不到该头文件,编译时会报错。该头文件应该只是个声明啥的,可以自己写。我是用linux 交叉编译工具编译另外一个目录下的ffmpeg_3.1.1之后,在该目录生成了ffversion.h文件,将该文件拷贝到jni/ffmpeg_3.1.1/libavutil/目录下。
ffversion.h头文件很简单,就一个宏,可自动创建,内容如下:
#ifndef AVUTIL_FFVERSION_H #define AVUTIL_FFVERSION_H #define FFMPEG_VERSION "3.1.1" #endif /* AVUTIL_FFVERSION_H */
22.在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))
23.修改几个代码中的BUG
1. 将 libavcodec/movtextdec.c 文件中的第487行代码
for (size_t i = 0; i < box_count; i++) {
改为:
size_t i = 0; for (i = 0; i < box_count; i++) {
2.将 libavcodec/proresdec2.c 文件第597 行代码
for (size_t i = 0; i < 16; ++i) for (size_t j = 0; j < mb_max_x; ++j) { *(uint16_t*)(dest_u + (i * chroma_stride) + (j << 1)) = 511; *(uint16_t*)(dest_v + (i * chroma_stride) + (j << 1)) = 511; }
改为
size_t i = 0, j = 0; for (i = 0; i < 16; ++i) for (j = 0; j < mb_max_x; ++j) { *(uint16_t*)(dest_u + (i * chroma_stride) + (j << 1)) = 511; *(uint16_t*)(dest_v + (i * chroma_stride) + (j << 1)) = 511; }
因为C语音不支持在代码循环中定义变量。
24.准备工作完成,开始编译。
ndk-build
25.等待编译
等待大概十多分钟即可编译完成,编译完成后,会自动在jni上一级目录(本人的是/home/sk/local)生成libs 和obj文件夹。libs下面会有armeabi-v7a/libffmpeg.so 库文件,可以看下大小,编译出来大概是7.7M。结果如下:
到此所有工作已完成,可以开始编写jni在android上使用了。
写点东西不容易,请大家遵守原创。转载引用时请注明出处,谢谢!
借鉴文档:
http://www.cppblog.com/mikesheng/articles/203597.html
相关文章推荐
- DFS && BFS 最少步数(nyoj 58)
- linux下jdk的安装过程以及步奏
- Medoo的使用教程
- 欢迎使用CSDN-markdown编辑器
- QingCloud Insight 2016:诠释云计算未来图景
- cadence学习2—cadence 如何拷贝别人图纸中的原件封装
- 经典java面试题目
- C++中可调用对象
- 1800 假面舞会
- HDU5773(The All-purpose Zero LIS变形)
- 赛码网_在线编程_约会
- js的宽高度offsetWidth;clientWidth;
- 【杭电1242】广搜+队列
- JAVA中的Date类与Calendar类
- _bdhmProtocol 解释
- 网页应该设计为多少像素才合适?
- 【c++】Huffman实现文件压缩
- Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)
- 【置顶】博客更换~~~
- 工程一:记事本的实现