Android:WIN10+MinGW+NDK编译FFmpeg
2017-07-31 21:46
591 查看
前言:
Android音视频开发的话,FFmpeg总是必须的,出于学习目的,花时间起了个开头。
FFmpeg源码是很多的c文件,首先要借助工具编译出so库,仅有这个Android是无法调用的,必须再用JNI写一层Android能用的接口。网上资料非常多,但是看了几天下来,编译平台和工具版本的差异总是存在,编译过程中也有各种各样的问题。这里给出自己的编译过程,希望给刚好需要的同学。
到写文章为止,所有源码和工具都是用的最新版。
一.MinGW编译出so库
http://ffmpeg.org/下载源码,解压到一个文件夹里
![](https://oscdn.geek-share.com/Uploads/Images/Content/201908/07/1038ca33549fb3891ff9a4d1f29cbfe8)
https://sourceforge.net/projects/mingw/files/下载MinGW,把相应的选项都勾上,环境变量配置好。
找到ffmpeg目录下的configure
打开并找到以下几行
替换为
在ffmpeg下新建一个build_android.sh,将以下代码复制进去
1)前三行按实际情况替换
2)这里我用notepad++编辑将文件格式改为Unix格式,否则会有一些换行符等Windows与Linux平台差异问题编译出问题
之后打开下载好的MinGW的 MinGW\msys\1.0\msys.bat,执行以下命令
![](https://oscdn.geek-share.com/Uploads/Images/Content/201908/07/545daedc00f1306b9304d73362ba8ca6)
耐心等待后,ffmpeg下多出一个libs文件夹,里面就是我们想要的东西了
![](https://oscdn.geek-share.com/Uploads/Images/Content/201908/07/54a7520116bb62700b5ce01ed326fda4)
二.NDK编译JNI
还是在ffmpeg目录下,新建一个jni目录,里面是这些东西
![](https://oscdn.geek-share.com/Uploads/Images/Content/201908/07/725bd11cf293e40908b6c5fb0c794dfa)
其中Android.mk
Application.mk
jniloader.c
然后就用NDK编译即可,这就是我们最终要的了。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201908/07/6e785f3065acb32e3c8315c30eda9282)
三.Java层调用接口
把JNI编译出来的SO库放在jniLibs下
![](https://oscdn.geek-share.com/Uploads/Images/Content/201908/07/428e6ea3690bc85a82760201476d3b8d)
声明相关的c层函数并加载so库
![](https://oscdn.geek-share.com/Uploads/Images/Content/201908/07/9f5e0fafb1eb71ce94f0c3e7474a5e99)
最后调用即可,这些都只是简单的用ffmpeg提供的函数输出相关的配置信息,还有很多强大的音视频相关的功能要慢慢探索了。
Android音视频开发的话,FFmpeg总是必须的,出于学习目的,花时间起了个开头。
FFmpeg源码是很多的c文件,首先要借助工具编译出so库,仅有这个Android是无法调用的,必须再用JNI写一层Android能用的接口。网上资料非常多,但是看了几天下来,编译平台和工具版本的差异总是存在,编译过程中也有各种各样的问题。这里给出自己的编译过程,希望给刚好需要的同学。
到写文章为止,所有源码和工具都是用的最新版。
一.MinGW编译出so库
http://ffmpeg.org/下载源码,解压到一个文件夹里
https://sourceforge.net/projects/mingw/files/下载MinGW,把相应的选项都勾上,环境变量配置好。
找到ffmpeg目录下的configure
打开并找到以下几行
SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)' LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"' SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)' SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR)$(SLIBNAME)'
替换为
SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)' LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"' SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)' SLIB_INSTALL_LINKS='$(SLIBNAME)'
在ffmpeg下新建一个build_android.sh,将以下代码复制进去
1)前三行按实际情况替换
2)这里我用notepad++编辑将文件格式改为Unix格式,否则会有一些换行符等Windows与Linux平台差异问题编译出问题
#!/bin/sh NDK=D:/Program/android-ndk-r14b SYSROOT=$NDK/platforms/Android-21/arch-arm TOOLCHAIN=$NDK/toolchains/arm-Linux-androideabi-4.9/prebuilt/windows-x86_64 function build_one { ./configure \ --prefix=$PREFIX \ --enable-shared \ --enable-gpl \ --disable-static \ --disable-doc \ --disable-ffmpeg \ --disable-ffplay \ --disable-ffprobe \ --disable-ffserver \ --disable-doc \ --disable-symver \ --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \ --target-os=linux \ --arch=arm \ --enable-cross-compile \ --sysroot=$SYSROOT \ --extra-cflags="-Os -fpic $ADDI_CFLAGS" \ --extra-ldflags="$ADDI_LDFLAGS" \ $ADDITIONAL_CONFIGURE_FLAG make clean make make install } CPU=arm PREFIX=$(pwd)/libs/$CPU ADDI_CFLAGS="-marm" build_one
之后打开下载好的MinGW的 MinGW\msys\1.0\msys.bat,执行以下命令
耐心等待后,ffmpeg下多出一个libs文件夹,里面就是我们想要的东西了
二.NDK编译JNI
还是在ffmpeg目录下,新建一个jni目录,里面是这些东西
其中Android.mk
APP_ALLOW_MISSING_DEPS=true LOCAL_PATH := $(call my-dir) # FFmpeg library include $(CLEAR_VARS) LOCAL_MODULE := avcodec LOCAL_SRC_FILES := libavcodec-57.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := avfilter LOCAL_SRC_FILES := libavfilter-6.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := avformat LOCAL_SRC_FILES := libavformat-57.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := avutil LOCAL_SRC_FILES := libavutil-55.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := swscale LOCAL_SRC_FILES := libswscale-4.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := swresample LOCAL_SRC_FILES := libswresample-2.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := avdevice LOCAL_SRC_FILES := libavdevice-57.so include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := postproc LOCAL_SRC_FILES := libpostproc-54.so include $(PREBUILT_SHARED_LIBRARY) # Program include $(CLEAR_VARS) LOCAL_MODULE := jniloader LOCAL_SRC_FILES := jniloader.c LOCAL_C_INCLUDES += $(LOCAL_PATH)/include LOCAL_LDLIBS := -llog -lz LOCAL_SHARED_LIBRARIES := avcodec avdevice avfilter avformat avutil postproc swresample swscale include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_ABI :=armeabi
jniloader.c
#include <stdio.h> #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libavfilter/avfilter.h" #ifdef ANDROID #include <jni.h> #include <android/log.h> #endif struct URLProtocol; JNIEXPORT jstring Java_com_example_ffmpeg_JNILoader_urlprotocolinfo(JNIEnv *env, jobject obj){ char info[40000]={0}; av_register_all(); struct URLProtocol *pup = NULL; //Input struct URLProtocol **p_temp = &pup; avio_enum_protocols((void **)p_temp, 0); while ((*p_temp) != NULL){ sprintf(info, "%s[In ][%10s]\n", info, avio_enum_protocols((void **)p_temp, 0)); } pup = NULL; //Output avio_enum_protocols((void **)p_temp, 1); while ((*p_temp) != NULL){ sprintf(info, "%s[Out][%10s]\n", info, avio_enum_protocols((void **)p_temp, 1)); } //LOGE("%s", info); return (*env)->NewStringUTF(env, info); } JNIEXPORT jstring Java_com_example_ffmpeg_JNILoader_avformatinfo(JNIEnv *env, jobject obj){ char info[40000] = { 0 }; av_register_all(); AVInputFormat *if_temp = av_iformat_next(NULL); AVOutputFormat *of_temp = av_oformat_next(NULL); //Input while(if_temp!=NULL){ sprintf(info, "%s[In ][%10s]\n", info, if_temp->name); if_temp=if_temp->next; } //Output while (of_temp != NULL){ sprintf(info, "%s[Out][%10s]\n", info, of_temp->name); of_temp = of_temp->next; } //LOGE("%s", info); return (*env)->NewStringUTF(env, info); } JNIEXPORT jstring Java_com_example_ffmpeg_JNILoader_avcodecinfo(JNIEnv *env, jobject obj) { char info[40000] = { 0 }; av_register_all(); AVCodec *c_temp = av_codec_next(NULL); while(c_temp!=NULL){ if (c_temp->decode!=NULL){ sprintf(info, "%s[Dec]", info); } else{ sprintf(info, "%s[Enc]", info); } switch (c_temp->type){ case AVMEDIA_TYPE_VIDEO: sprintf(info, "%s[Video]", info); break; case AVMEDIA_TYPE_AUDIO: sprintf(info, "%s[Audio]", info); break; default: sprintf(info, "%s[Other]", info); break; } sprintf(info, "%s[%10s]\n", info, c_temp->name); c_temp=c_temp->next; } //LOGE("%s", info); return (*env)->NewStringUTF(env, info); } JNIEXPORT jstring Java_com_example_ffmpeg_JNILoader_avfilterinfo(JNIEnv *env, jobject obj) { char info[40000] = { 0 }; avfilter_register_all(); AVFilter *f_temp = (AVFilter *)avfilter_next(NULL); while (f_temp != NULL){ sprintf(info, "%s[%10s]\n", info, f_temp->name); f_temp = f_temp->next; } //LOGE("%s", info); return (*env)->NewStringUTF(env, info); } JNIEXPORT jstring Java_com_example_ffmpeg_JNILoader_configurationinfo(JNIEnv *env, jobject obj) { char info[10000] = { 0 }; av_register_all(); sprintf(info, "%s\n", avcodec_configuration()); //LOGE("%s", info); return (*env)->NewStringUTF(env, info); }
然后就用NDK编译即可,这就是我们最终要的了。
三.Java层调用接口
把JNI编译出来的SO库放在jniLibs下
声明相关的c层函数并加载so库
最后调用即可,这些都只是简单的用ffmpeg提供的函数输出相关的配置信息,还有很多强大的音视频相关的功能要慢慢探索了。
相关文章推荐
- Android android-ndk-r8b 编译 FFMPEG 2.5
- Ubuntu12.04 32位 + android-ndk-r9c 编译ffmpeg遇到的问题记录
- MAC系统下利用NDK编译可供Android使用的FFmpeg(3.2.4)库
- windows环境 cygwin android-ndk-r7 编译 ffmpeg
- 使用NDK交叉编译ffmpeg, android后台可执行。
- linux中使用NDK编译ffmpeg的android平台的可执行文件
- Android-NDK-r9编译ffmpeg-0.11.3
- Ubuntu下用NDK编译移植FFmpeg 2.0(配置最新版x264)到Android平台
- 使用ubuntu14和ndk 编译ffmpeg在android平台的so动态库
- window7 android-ndk-r10d 编译ffmpeg 3.4
- buntu12.10 64位 + android-ndk-r9 编译ffmpeg遇到的问题
- Android本地视频播放器开发--NDK编译FFmpeg
- 用 NDK 编译 ffmpeg 到 Android 平台
- android-ndk-r7 编译 ffmpeg-0.10
- buntu12.10 64位 + android-ndk-r9 编译ffmpeg遇到的问题
- Android本地视频播放器开发--NDK编译FFmpeg
- Ubuntu 下用NDK编译移植 ffmpeg 2.0 (配置最新版x264) 到android平台
- Android本地视频播放器开发--NDK编译FFmpeg
- ffmpeg2.2在ubuntu下使用NDK编译——并在android工程下测试使用