基础环境
- MacOS 10.12.3
- AndroidStudio 2.3
- NDK 13.1.*
- FFmpeg 3.2.*
下载 FFmpeg 源码
1 | git clone https://git.ffmpeg.org/ffmpeg.git |
---|
切换到 3.2 分支
1 | git checkout -b 3.2 remotes/origin/release/3.2 |
---|
当然你也可以去去官网下载压缩包。
编译 FFmpeg for Android
修改 FFmpeg 的 configure
打开 configure 文件,找到:
1234 | 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)' |
---|
替换成:
代码语言:javascript复制1234SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'SLIB_INSTALL_LINKS='$(SLIBNAME)'
编写 Android 编译脚本
123456789101112131415161718192021222324252627282930313233343536373839 | #!/bin/bashNDK=/Users/gavin/Develop/android-sdk/ndk-bundleSYSROOT=$NDK/platforms/android-15/arch-arm/TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64CPU=armPREFIX=$(pwd)/android/$CPU ADDI_CFLAGS="-marm"function build_one{./configure --prefix=$PREFIX --enable-shared --disable-static --disable-doc --disable-ffmpeg --disable-ffplay --disable-ffprobe --disable-ffserver --disable-avdevice --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_FLAGmake cleanmakemake install}build_one |
---|
前三行自行更换成自己的 NDK 路径即可,PREFIX 就是最终编译输出地址,根据情况也可以修改。
保存文件到 FFmpeg 根目录为 build_android.sh
,chmod x build_android.sh
赋予执行权限。
编译
执行脚本进行编译。
1 | ./build_android.sh |
---|
小憩一会儿,编译完成。 进入 PREFIX 目录:
123456789101112131415 | ── include│ ├── libavcodec│ ├── libavfilter│ ├── libavformat│ ├── libavutil│ ├── libswresample│ └── libswscale└── lib├── libavcodec-57.so├── libavfilter-6.so├── libavformat-57.so├── libavutil-55.so├── libswresample-2.so├── libswscale-4.so└── pkgconfig |
---|
我们需要的 so 和头文件都有啦。
导入 Android 工程
对于如何开始一个 C 项目,官方已经有中文文档了:
https://developer.android.google.cn/studio/projects/add-native-code.html
官网有的东西不赘述,再次声明学什么东西优先看 官方文档,官方文档,官方文档,并且Google dev现在已经有很多中文资源了。
新建一个 C/C 工程
勾选 Include C Support 即可得到一个基于CMake的模板工程。
拷贝 so 和 incude 文件到 libs
因为我们只编译了 arm 版本的 so,所以需要把 so 拷到 armeabi-v7a 目录下,完整路径如下:
1234567891011121314151617181920212223 | ├── build.gradle├── libs│ ├── armeabi-v7a│ │ ├── libavcodec-57.so│ │ ├── libavfilter-6.so│ │ ├── libavformat-57.so│ │ ├── libavutil-55.so│ │ ├── libswresample-2.so│ │ └── libswscale-4.so│ └── include│ ├── libavcodec│ ├── libavfilter│ ├── libavformat│ ├── libavutil│ ├── libswresample│ └── libswscale├── proguard-rules.pro└── src└── main├── AndroidManifest.xml├── cpp├── java└── res |
---|
指定 jniLibs 路径
12345678 | android {...sourceSets {main {jniLibs.srcDirs = ['libs']}}} |
---|
指定 abiFilters
因为 so 只有 armeabi-v7a 的,所以我们还需要指定一下 abi 为 armeabi-v7a
123456789 | android {...defaultConfig {...ndk {abiFilters 'armeabi-v7a'}}} |
---|
编写 CMakeLists
脚本怎么写,有什么讲究其实官方文档已经很清楚了:创建 CMake 构建脚本
https://developer.android.google.cn/studio/projects/add-native-code.html#create-cmake-script
Java 引入 so 库
12345678910 | static {System.loadLibrary("native-lib");System.loadLibrary("avcodec-57");System.loadLibrary("avfilter-6");System.loadLibrary("avformat-57");System.loadLibrary("avutil-55");System.loadLibrary("swresample-2");System.loadLibrary("swscale-4");} |
---|
运行测试
如果成功运行不报错的话,就证明一切没有问题。
编写 FFmpeg 测试代码
UI
C
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 | #include <jni.h>#include <string>extern "C" {#include <libavcodec/avcodec.h>#include <libavformat/avformat.h>#include <libavfilter/avfilter.h>JNIEXPORT jstring JNICALLJava_cn_gavinliu_android_ffmpeg_MainActivity_stringFromJNI(JNIEnv *env,jobject /* this */) {std::string hello = "Hello from C ";return env->NewStringUTF(hello.c_str());}JNIEXPORT jstring JNICALLJava_cn_gavinliu_android_ffmpeg_MainActivity_avformatinfo(JNIEnv *env,jobject /* this */) {char info[40000] = {0};av_register_all();AVInputFormat *if_temp = av_iformat_next(NULL);AVOutputFormat *of_temp = av_oformat_next(NULL);while (if_temp != NULL) {sprintf(info, "%sInput: %sn", info, if_temp->name);if_temp = if_temp->next;}while (of_temp != NULL) {sprintf(info, "%sOutput: %sn", info, of_temp->name);of_temp = of_temp->next;}return env->NewStringUTF(info);}JNIEXPORT jstring JNICALLJava_cn_gavinliu_android_ffmpeg_MainActivity_urlprotocolinfo(JNIEnv *env,jobject /* this */) {char info[40000] = {0};av_register_all();struct URLProtocol *pup = NULL;struct URLProtocol **p_temp = &pup;avio_enum_protocols((void **) p_temp, 0);while ((*p_temp) != NULL) {sprintf(info, "%sInput: %sn", info, avio_enum_protocols((void **) p_temp, 0));}pup = NULL;avio_enum_protocols((void **) p_temp, 1);while ((*p_temp) != NULL) {sprintf(info, "%sInput: %sn", info, avio_enum_protocols((void **) p_temp, 1));}return env->NewStringUTF(info);}JNIEXPORT jstring JNICALLJava_cn_gavinliu_android_ffmpeg_MainActivity_avcodecinfo(JNIEnv *env,jobject /* this */) {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, "%sdecode:", info);} else {sprintf(info, "%sencode:", 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[s]n", info, c_temp->name);c_temp = c_temp->next;}return env->NewStringUTF(info);}JNIEXPORT jstring JNICALLJava_cn_gavinliu_android_ffmpeg_MainActivity_avfilterinfo(JNIEnv *env, jobject /* this */) {char info[40000] = {0};avfilter_register_all();AVFilter *f_temp = (AVFilter *) avfilter_next(NULL);while (f_temp != NULL) {sprintf(info, "%s%sn", info, f_temp->name);f_temp = f_temp->next;}return env->NewStringUTF(info);}} |
---|
运行
更多
最简单的基于FFmpeg的移动端例子:Android HelloWorld http://blog.csdn.net/leixiaohua1020/article/details/47008825 FFmpeg 教程 http://blog.csdn.net/column/details/ffmpeg-devel.html