最近想從事音視頻方面的開發(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兼容的趴俘。下載后解壓可以得三個文件夾:
我們需要集成的都是個文件夾里的東西志珍。下面就開始新建Android項目
這里勾選了c++支持,因為后面還要集成FFmpeg
一路完成后橙垢,就會獲得一個新的Android項目,這下你可以試著運行一下伦糯。
下面就是導(dǎo)入OpenCV SDK了柜某。
選擇[File]->[New]->Import Module... 然后再選擇OpenCV SDK目錄里面的sdk/java目錄,這里系統(tǒng)會自動當(dāng)前OpenCV的版本敛纲,如下圖
因為我用新項目發(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
然后在app目錄下新建libs文件夾,將OpenCV Android SDK目錄native/libs里面所有的文件復(fù)制到app的libs文件夾里面裁奇。注意這里只有so文件桐猬,沒有a文件。
然后再修改這兩個build.gradle文件
將兩個文件里面的minSdkVersion改成21刽肠,targetSdkVersion改成26溃肪,(其實這個是要看項目情況的,改成其他值也行音五,但是要一至)
最后一步就是在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目錄下
再在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文件
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)信息
到此已經(jīng)全部完成Android Studio集成OpenCV和FFmpeg。 目前我還是初步學(xué)習(xí)階段萎坷,集成成功之后還要在這方面投入很多時間來學(xué)習(xí)凹联。接下來需要總結(jié)iOS平臺怎么集成OpenCV和FFmpeg。最后再次放出項目地址哆档。