Android Studio集成FFmpeg和OpenCV

Android Studio集成FFmpeg和OpenCV

最近想從事音視頻方面的開發(fā)党窜,所以研究了FFmpeg和OpenCV罩息,主要是家里沒有Mac荞胡,所以就想用安卓平臺學(xué)學(xué)習(xí)。這時就需要Android Studio集成FFmpeg和OpenCV娱局。折騰了好一會彰亥,終于可以使用了。下面分享一下怎么使用最新的Android Studio3.2版本來集成FFmpeg和OpenCV衰齐,相關(guān)項目的鏈接在此任斋。因為編譯好的OpenCV和FFmpeg文件非常大,所以我沒有上傳到Github里耻涛,而是放到了網(wǎng)盤里,讀者可以在這里下載該項目的相關(guān)文件废酷。下面所有代碼都在小米平板4上和小米8上測試通過,還有華為和OPPO的一些機器抹缕。

首先是集成OpenCV,這相對于FFmpeg來說要簡單不少澈蟆。官網(wǎng)已經(jīng)提供編譯好的各種平臺so文件下載。opencv-android下載頁面,這里說一下版本問題卓研,一般官網(wǎng)提供的最新版本都是可以和目前最新的Android Studio兼容的趴俘。下載后解壓可以得三個文件夾:

解壓的OpenCV目錄

其中sample應(yīng)該是樣列了,apk里面是各平臺的OpenCV Manager APP安裝文件奏赘,不知道有什么用寥闪。sdk文件夾是我們最需要關(guān)心的。
sdk文件夾里的東西

我們需要集成的都是個文件夾里的東西志珍。下面就開始新建Android項目

新項目

這里勾選了c++支持,因為后面還要集成FFmpeg


從Android5開始支持
空白項目

一路完成后橙垢,就會獲得一個新的Android項目,這下你可以試著運行一下伦糯。
下面就是導(dǎo)入OpenCV SDK了柜某。


import OpenCV SDK

選擇[File]->[New]->Import Module... 然后再選擇OpenCV SDK目錄里面的sdk/java目錄,這里系統(tǒng)會自動當(dāng)前OpenCV的版本敛纲,如下圖


導(dǎo)入OpenCV,其版本為3.4.3
因為我用新項目發(fā)現(xiàn)Gradle總是報錯喂击,不想浪費時間調(diào)了,我就用我自己項目來示列吧(我自己項目沒有加上343這個版本號)

然后在你的app->build.gradle->dependencies里加上 implementation project(':OpenCVLibrary343') 也就是你剛導(dǎo)入的Module的名字

這時選擇[File]->[Project Structure...] 選擇APP淤翔,右邊的選項卡選擇 [Dependencies]可以看到最下面已經(jīng)有了該模塊翰绊,如果沒有, 也可以在這里手動添加。點擊下面的+监嗜,選擇Module Dependency谐檀,再選擇OpenCV


添加OpenCV Module dependency

然后在app目錄下新建libs文件夾,將OpenCV Android SDK目錄native/libs里面所有的文件復(fù)制到app的libs文件夾里面裁奇。注意這里只有so文件桐猬,沒有a文件。


libs目錄下的OpenCV動態(tài)庫

然后再修改這兩個build.gradle文件


兩個build.gradle文件

將兩個文件里面的minSdkVersion改成21刽肠,targetSdkVersion改成26溃肪,(其實這個是要看項目情況的,改成其他值也行音五,但是要一至)


修改minSdkVersion和targetSdkVersion

最后一步就是在Module:app對應(yīng)的build.gradle文件加入以下內(nèi)容惫撰,注意是在android標(biāo)簽里
    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標(biāo)簽里)

implementation fileTree(dir: "$buildDir/native-libs", include: 'native-libs.jar')

至此Android Studio已經(jīng)配置好了OpenCV開發(fā)環(huán)境,接下來清空項目躺涝,然后寫代碼來驗證一下環(huán)境配置厨钻。

在MainActivity對應(yīng)的布局XML文件中加入一個Button按鈕一張圖片,圖片加載本地一張圖片坚嗜,然后在MainActivity中為該Button添加一個事件莉撇,使該圖片變成灰階圖片。上面的代碼我就不列出來了惶傻,都是最基礎(chǔ)的。不過在此之前其障,需要在該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方法里調(diào)用這個方法。再在Button的響應(yīng)事件里寫以下代碼

        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()

代碼完成励翼,啟動真機調(diào)試蜈敢,不出意外就可以看到該圖片變灰了。

成功將一張圖片變成灰階

我發(fā)現(xiàn)有的機器上使用OpenCV非称В卡抓狭,比如紅米Note4X 但是配置更低的華為和Oppo手機確不會有這種問題,目前還不清楚為什么會這樣造烁。

好了否过,OpenCV的集成工作到此就完成了,下面將繼續(xù)集成FFmpeg惭蟋,一般是先要將FFMpeg的源代碼編譯成Android所需要的so和頭文件苗桂,但是我使用最新的FFmpeg源代碼和NDK總是編譯出現(xiàn)問題,折騰了好幾天就放棄了告组,使用了別人編譯好的文件煤伟。
首先將下載好的ffmpeg_opencv_android文件解壓,里面有三個夾,其中l(wèi)ibs是OpenCV相關(guān)文件便锨,這里就不用管了围辙,jniLibs是編譯好的FFmpeg文件,cpp里是FFmpeg頭文件放案,這里需要將要這兩個文件夾拖到項目目錄->app->src->main目錄下


放置好的FFmpeg相關(guān)文件

再在app目錄下添加CMakeLists.txt文件姚建,在里面添加以下內(nèi)容

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} )

這里面的設(shè)置參數(shù)其他我也不懂,有興趣有同學(xué)可以搜索相關(guān)文章了解卿叽。
接下來就是修改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成功
最后就是實現(xiàn)C++的ffmpegInfo橋接方法了沥阱,在cpp目錄下的已經(jīng)存在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報錯策精,可以從錯誤信息找到正確的方法全名。
關(guān)于JNI這方面我還不太懂崇棠,所以我也是參考別人的教程寫的咽袜,只不過我用了Kotlin實現(xiàn)了。最后讓我們來寫代碼測試是FFmpeg是否集成成功
在一個空的頁面添加一個占整個頁面的TextView枕稀,然后在進入這個頁面時添加以下代碼

 txtfinfo.text = FFmpegBridge.ffmpegInfo()

就這一行就行了
啟動真機調(diào)試询刹,進入該頁面后不出意外就可以看到打印出的FFmpeg相關(guān)信息


FFmpeg集成成功后獲取的信息

到此已經(jīng)全部完成Android Studio集成OpenCV和FFmpeg。 目前我還是初步學(xué)習(xí)階段萎坷,集成成功之后還要在這方面投入很多時間來學(xué)習(xí)凹联。接下來需要總結(jié)iOS平臺怎么集成OpenCV和FFmpeg。最后再次放出項目地址哆档。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蔽挠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子瓜浸,更是在濱河造成了極大的恐慌澳淑,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件插佛,死亡現(xiàn)場離奇詭異偶惠,居然都是意外死亡,警方通過查閱死者的電腦和手機朗涩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門忽孽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事兄一±逑撸” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵出革,是天一觀的道長造壮。 經(jīng)常有香客問我,道長骂束,這世上最難降的妖魔是什么耳璧? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮展箱,結(jié)果婚禮上旨枯,老公的妹妹穿的比我還像新娘。我一直安慰自己混驰,他們只是感情好攀隔,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著栖榨,像睡著了一般昆汹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上婴栽,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天满粗,我揣著相機與錄音,去河邊找鬼愚争。 笑死败潦,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的准脂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼檬洞,長吁一口氣:“原來是場噩夢啊……” “哼狸膏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起添怔,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤湾戳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后广料,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體砾脑,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年艾杏,在試婚紗的時候發(fā)現(xiàn)自己被綠了韧衣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖畅铭,靈堂內(nèi)的尸體忽然破棺而出氏淑,到底是詐尸還是另有隱情,我是刑警寧澤硕噩,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布假残,位于F島的核電站,受9級特大地震影響炉擅,放射性物質(zhì)發(fā)生泄漏辉懒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一谍失、第九天 我趴在偏房一處隱蔽的房頂上張望眶俩。 院中可真熱鬧,春花似錦袱贮、人聲如沸仿便。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嗽仪。三九已至,卻和暖如春柒莉,著一層夾襖步出監(jiān)牢的瞬間闻坚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工兢孝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留窿凤,地道東北人。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓跨蟹,卻偏偏與公主長得像雳殊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子窗轩,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容