美文网首页framework
Android Studio集成FFmpeg和OpenCV

Android Studio集成FFmpeg和OpenCV

作者: 黑暗中的孤影 | 来源:发表于2018-11-27 17:04 被阅读296次
    Android Studio集成FFmpeg和OpenCV

    最近想从事音视频方面的开发,所以研究了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兼容的。下载后解压可以得三个文件夹:

    解压的OpenCV目录 其中sample应该是样列了,apk里面是各平台的OpenCV Manager APP安装文件,不知道有什么用。sdk文件夹是我们最需要关心的。 sdk文件夹里的东西

    我们需要集成的都是个文件夹里的东西。下面就开始新建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。最后再次放出项目地址

    相关文章

      网友评论

        本文标题:Android Studio集成FFmpeg和OpenCV

        本文链接:https://www.haomeiwen.com/subject/htvxxqtx.html