最近想从事音视频方面的开发,所以研究了FFmpeg和OpenCV,主要是家里没有Mac,所以就想用安卓平台学学习。这时就需要Android Studio集成FFmpeg和OpenCV。折腾了好一会,终于可以使用了。下面分享一下怎么使用最新的Android Studio3.2版本来集成FFmpeg和OpenCV,相关项目的链接在此。因为编译好的OpenCV和FFmpeg文件非常大,所以我没有上传到Github里,而是放到了网盘里,读者可以在这里下载该项目的相关文件。下面所有代码都在小米平板4上和小米8上测试通过,还有华为和OPPO的一些机器。
首先是集成OpenCV,这相对于FFmpeg来说要简单不少。官网已经提供编译好的各种平台so文件下载。opencv-android下载页面,这里说一下版本问题,一般官网提供的最新版本都是可以和目前最新的Android Studio兼容的。下载后解压可以得三个文件夹:
我们需要集成的都是个文件夹里的东西。下面就开始新建Android项目
新项目这里勾选了c++支持,因为后面还要集成FFmpeg
从Android5开始支持 空白项目
一路完成后,就会获得一个新的Android项目,这下你可以试着运行一下。
下面就是导入OpenCV SDK了。
import OpenCV SDK
选择[File]->[New]->Import Module... 然后再选择OpenCV SDK目录里面的sdk/java目录,这里系统会自动当前OpenCV的版本,如下图
导入OpenCV,其版本为3.4.3
因为我用新项目发现Gradle总是报错,不想浪费时间调了,我就用我自己项目来示列吧(我自己项目没有加上343这个版本号)
然后在你的app->build.gradle->dependencies里加上 implementation project(':OpenCVLibrary343') 也就是你刚导入的Module的名字
这时选择[File]->[Project Structure...] 选择APP,右边的选项卡选择 [Dependencies]可以看到最下面已经有了该模块,如果没有, 也可以在这里手动添加。点击下面的+,选择Module Dependency,再选择OpenCV
添加OpenCV Module dependency
然后在app目录下新建libs文件夹,将OpenCV Android SDK目录native/libs里面所有的文件复制到app的libs文件夹里面。注意这里只有so文件,没有a文件。
libs目录下的OpenCV动态库
然后再修改这两个build.gradle文件
两个build.gradle文件
将两个文件里面的minSdkVersion改成21,targetSdkVersion改成26,(其实这个是要看项目情况的,改成其他值也行,但是要一至)
修改minSdkVersion和targetSdkVersion
最后一步就是在Module:app对应的build.gradle文件加入以下内容,注意是在android标签里
task nativeLibsToJar(type: Jar, description: 'create a jar archive of the native libs') {
destinationDir file("$buildDir/native-libs")
baseName 'native-libs'
from fileTree(dir: 'libs', include: '**/*.so')
into 'lib/'
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn(nativeLibsToJar)
}
然后在编译片段添加台下代码(dependencies标签里)
implementation fileTree(dir: "$buildDir/native-libs", include: 'native-libs.jar')
至此Android Studio已经配置好了OpenCV开发环境,接下来清空项目,然后写代码来验证一下环境配置。
在MainActivity对应的布局XML文件中加入一个Button按钮一张图片,图片加载本地一张图片,然后在MainActivity中为该Button添加一个事件,使该图片变成灰阶图片。上面的代码我就不列出来了,都是最基础的。不过在此之前,需要在该Activity加载OpenCV本地库。
private fun loadOpenCV(){
val success = OpenCVLoader.initDebug()
if (success){
Log.i("cvtag","OpenCV Libraries loaded...")
}
else{
Toast.makeText(this.applicationContext,"Warning:Could not load the OpenCV Libraries", Toast.LENGTH_SHORT).show()
}
}
在onCreate方法里调用这个方法。再在Button的响应事件里写以下代码
imgGray.isDrawingCacheEnabled = true //the id of the imageview
val bitmap = Bitmap.createBitmap(imgGray.drawingCache)
imgGray.isDrawingCacheEnabled = false
val src = Mat()
val dst = Mat()
Utils.bitmapToMat(bitmap,src)
Imgproc.cvtColor(src,dst, Imgproc.COLOR_BGRA2GRAY)
Utils.matToBitmap(dst,bitmap)
imgGray.setImageBitmap(bitmap)
src.release()
dst.release()
代码完成,启动真机调试,不出意外就可以看到该图片变灰了。
成功将一张图片变成灰阶我发现有的机器上使用OpenCV非常卡,比如红米Note4X 但是配置更低的华为和Oppo手机确不会有这种问题,目前还不清楚为什么会这样。
好了,OpenCV的集成工作到此就完成了,下面将继续集成FFmpeg,一般是先要将FFMpeg的源代码编译成Android所需要的so和头文件,但是我使用最新的FFmpeg源代码和NDK总是编译出现问题,折腾了好几天就放弃了,使用了别人编译好的文件。
首先将下载好的ffmpeg_opencv_android文件解压,里面有三个夹,其中libs是OpenCV相关文件,这里就不用管了,jniLibs是编译好的FFmpeg文件,cpp里是FFmpeg头文件,这里需要将要这两个文件夹拖到项目目录->app->src->main目录下
放置好的FFmpeg相关文件
再在app目录下添加CMakeLists.txt文件,在里面添加以下内容
cmake_minimum_required(VERSION 3.4.1)
#set(distribution_DIR ${CMAKE_SOURCE_DIR}/libs) # 文件夹为libs的情况下
set(distribution_DIR ${CMAKE_SOURCE_DIR}/src/main/jniLibs) # 文件夹为jniLibs的情况下
message("distribution_DIR:" ${distribution_DIR})
add_library( libavcodec
SHARED
IMPORTED )
add_library( libavfilter
SHARED
IMPORTED )
add_library( libavformat
SHARED
IMPORTED )
add_library( libavutil
SHARED
IMPORTED )
add_library( libswresample
SHARED
IMPORTED )
add_library( libswscale
SHARED
IMPORTED )
set_target_properties( libavcodec
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libavcodec.so)
set_target_properties( libavfilter
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libavfilter.so)
set_target_properties( libavformat
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libavformat.so)
set_target_properties( libavutil
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libavutil.so)
set_target_properties( libswresample
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libswresample.so)
set_target_properties( libswscale
PROPERTIES IMPORTED_LOCATION
${distribution_DIR}/${ANDROID_ABI}/libswscale.so)
add_library(
native-lib
SHARED
${CMAKE_SOURCE_DIR}/src/main/cpp/native-lib.cpp) #如果是C++则为native-lib.cpp
find_library(
log-lib
log)
include_directories(src/main/cpp/include)
target_link_libraries( # Specifies the target library.
native-lib
libavcodec
libavfilter
libavformat
libavutil
libswresample
libswscale
${log-lib} )
这里面的设置参数其他我也不懂,有兴趣有同学可以搜索相关文章了解。
接下来就是修改app目录下的build.gradle文件
修改好的build.gradle文件
sourceSets {
main {
jniLibs.srcDirs = ['src/main/jniLibs']
}
}
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
}
}
externalNativeBuild {
//配置CMakeLists文件地址
cmake {
path 'CMakeLists.txt'
}
}
这样基本就配置完成了,下面写代码测试一下
和iOS不一样,在Android项目里写C++代码更麻烦点,新建一个Kotlin和C++相互操作的桥接文件FFmpegBridge.kt文件,在里面加载各个FFmpeg库
class FFmpegBridge{
companion object {
init {
System.loadLibrary("avutil");
System.loadLibrary("fdk-aac");
System.loadLibrary("avcodec");
System.loadLibrary("avformat");
System.loadLibrary("swscale");
System.loadLibrary("swresample");
System.loadLibrary("avfilter");
System.loadLibrary("native-lib")
}
external fun ffmpegInfo(): String
}
}
可以看见Kotlin的语法和Java还是有比较大的差距的,这里的桥接方法是external fun ffmpegInfo(): String
用来测试项目是否集成FFmpeg成功
最后就是实现C++的ffmpegInfo桥接方法了,在cpp目录下的已经存在native-lib.cpp文件,打开该文件添加以下方法
#include <jni.h>
#include <android/log.h>
//编码
#ifdef __cplusplus
extern "C"
{
#endif
#include "include/libavcodec/avcodec.h"
//封装格式处理
#include "include/libavformat/avformat.h"
//像素处理
#include "include/libswscale/swscale.h"
JNIEXPORT jstring JNICALL
Java_stan_androiddemo_tool_ffmpeg_FFmpegBridge_00024Companion_ffmpegInfo(JNIEnv *env,jobject) {
char info[10000] = { 0 };
sprintf(info, "%s\n", avcodec_configuration());
return env->NewStringUTF(info);
}
#ifdef __cplusplus
}
#endif
注意这里,因为是写C++所以以加上#ifdef __cplusplus
,还有就上方法命名一定要按命名空间+类名+方法名
的形式,如果你不知道怎么命名可以先跑一次代码让Android Stduio报错,可以从错误信息找到正确的方法全名。
关于JNI这方面我还不太懂,所以我也是参考别人的教程写的,只不过我用了Kotlin实现了。最后让我们来写代码测试是FFmpeg是否集成成功
在一个空的页面添加一个占整个页面的TextView,然后在进入这个页面时添加以下代码
txtfinfo.text = FFmpegBridge.ffmpegInfo()
就这一行就行了
启动真机调试,进入该页面后不出意外就可以看到打印出的FFmpeg相关信息
FFmpeg集成成功后获取的信息
到此已经全部完成Android Studio集成OpenCV和FFmpeg。 目前我还是初步学习阶段,集成成功之后还要在这方面投入很多时间来学习。接下来需要总结iOS平台怎么集成OpenCV和FFmpeg。最后再次放出项目地址。
网友评论