AndroidStudio NDK的接入FFmpeg填坑记

近一周的时间里,由于项目中需要用到FFmpeg(一款强大的音视频操作开源项目,据说可以用来写播放器什么的)编解码项目,这么大牛的项目又是开源的注定是十分复杂的,所以在Android接入这一方面还是又机智的大牛做了尝试的,android接入 不过这是接入Skype的silk编码,以及这个大牛的文章。不过道理都是一样的,废话不多说!进入主题,

一.环境准备

Ubuntu 16.04;
ndk-r10d;
AndroidStudio(之后才意识到在sdkManager下载好的ndk比较快,推荐这种方式下载);
FFmpeg(注意选择版本下载)
具体的下载安装我就不说了 ,我们接入android是不需要将FFmpeg其在Ubuntu中编译的,主要源码就好,我第一次弄的时候就失足在Ubuntu中编译了FFmpeg,也无害。
如果不是在AndroidStudio中下载的ndk最好设置一下环境变量,然后指定ndk位置到项目。

二.在NDK中编译so

这个过程是比较麻烦的,有个大神的博客很好逝者已矣,愿天堂美好,盗用里面的一张图
这里写图片描述
整个步骤包括现将ffmpeg利用NDK编译成适应android指令集的动态库(这个依赖于c语言代码有没有适配不同的cpu指令集),通过编写JNI调用so库。其中图中的Moudule Source(*.c)部分就是原生c
语言调用so库。
首先修改configure配置文件,这只是ffmpeg需要这样做,其他的不同的库,最好参考REDEME文件,这个参考雷大神的博客这里写链接内容
我说说我遇到的坑,他的步骤是configure,make,make install三大步,在configure这一步的时候,书写的build脚本在执行的时候,总是出现未找到命令的提示,总是无法编译成功,经过google大神的帮助后,找到合适的解决方法,(这可是花了一天的时间啊!哭晕在厕所)网址是大神地址,编译成功后会在相应的文件夹中出现(在configure中设置)相应的so文件以及相应的头文件,编译完成后产生的相应的so文件,注意!配置文件如图:
AndroidStudio NDK的接入FFmpeg填坑记_第1张图片

时隔一年回头看这个博客,对这个build.sh也有了更深的理解,其实这个build.sh就是个命令脚本,在你的系统存在gcc环境下的一下编译命令集合。关于各个命令的具体意义还不是很了解,不过在这其中需要注意的是编译中遇到的各种问题的解决,比如:

1. 出现找不到文件,这是没有找到c标准类库,及其有可能是ndk的版本过高,将这个文件的位置更改了,需要手动指定位置,在build.sh文件中指定位置位置是得在ndk找到

2. 注意看文件路径,不要盲目的抄博客中的build,切记

三.在AndroidStudio中的java中接入so

这个过程首先我们得会写一个jni的helloworld,由于AndroidStudio在2.2后引进了CMake编译套件,加上之前的ndk的手动编译就有两种方式(CMake只是将编译的工作集成简化)运用ndk-build的方式建议之前推荐的雷大神的博客来操作,我在这里只说几点我的感悟。
1.Android.mk是编译知道文件需要理解
2.jni调用时函数的名称一定要按照规则来: Java_com_skystudio_ndkdemo_NativeUtils_strFromNdk( JNIEnv* env,jobject thiz )
3.ndk-build结束后可以将so文件放入jniLibs文件夹中,就可以将c源码删除了

四. 采用CMake方式接入FFmpeg

  1. 新建支持C++的Android project
  2. 将so库以及包含的头文件放置在正确的位置,其实也不一定是固定死的位置,只要你的CMakeList文件能够对应起来就是可以的,普遍的一种放置如图:AndroidStudio NDK的接入FFmpeg填坑记_第2张图片
  3. 重头戏来了就是编写CmakeList文件了,关于Cmake语法有很多内容,了解的也不够,只就这个需要用的含义解释一下,首先是cmake_minimum_required(VERSION 3.4.1),新建的时候会自带,必须要!
#添加库
add_library( # Sets the name of the library.添加编译后库的名字
             native

             # Sets the library as a shared library.设置库为动态库,static为静态库
             SHARED

             # Provides a relative path to your source file(s).设置编译库的源文件
             src/main/cpp/ffmpeg/native-lib.cpp )
             
 #ImPorted 引进已编译好的库
add_library( avfilter
             SHARED
             IMPORTED)
 #设置引进目标属性
set_target_properties( 
					#添加到的库名
					avfilter
					#引进地址,${CMKE_SOURCE_DIR}变量地址默认到项目名下,不知道在哪里设置
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi/libavfilter.so)

#设置头文件地址
include_directories(src/main/cpp/ffmpeg/include)
#指定目标库,就是最后确认项目用到的库意思
target_link_libraries( # Specifies the target library.
                        native
                        avcodec
                        avfilter
                        avformat
                        avutil
                        swresample
                        swscale

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )
  1. 然后就可以愉快的编译代码了(千万注意,地址的对应)

总结

  1. 问:什么叫交叉编译
    答:在某个平台上编译本平台可用的程序叫做本地编译,比如在windows平台上编译windows下的可执行程序。而交叉编译就是在某个平台上编译另一个平台程序。在Android中常用到在x86上编译arm平台上的程序。在交叉编译的时候由于平台差异性大,需要工具来解决这一问题,就出现了各种工具链,即Toolchains。而NDK就是提供了交叉编译的一整套工具的集合。
  2. 问:什么是ABI
    答:Application Binary Interface (应用程序二进制接口) 顾名思义就是应用程序与底层系统间的接口,它定义了程序如何与系统交互,所以我们需要指定不同类型cpu架构的ABI,即builde.gradle中的abiFilter{“x86”,“armeabi”“”}等。
  3. 问:什么是CMake,ndk-build,Android.mk
    答:这一块还不是很了解,推荐google官方文档

你可能感兴趣的:(android,Java)