26.Android Studio下Ndk開發(ffmpeg匯入Android studio以cmake方式編譯的過程)
Android studio 2.2開始支援cmake的方式進行jni開發,我在另一篇 ofollow,noindex">10.Eclipse下Ndk開發(ffmpeg解碼) 中寫過Eclipse下編譯ffmpeg的過程,但是現在幾乎沒有人會使用eclipse作為Android開發工具了,所以很有必要寫一下使用Android studio進行jni開發的一般步驟。
首要確保兩點:第一,你的Android studio 是2.2及以版本,第二,在你的sdk tools中,確保安裝了ndk,cmake,LLDB這三個東西。
其中LLDB是一個高效的c/c++的偵錯程式,目前LLDB也已經取代GDB成為XCode的預設偵錯程式,在Android studio中也可以使用。
CMake 則是一個跨平臺的編譯工具。

ndk配置.png
那麼我們如何進行開發呢,Android studio中專案的目錄結構又是怎樣安排,各有什麼意義?
android studio下cmake編譯ndk
新建專案時,新增c++支援很簡單,Android studio為我們提供了一個選項(Include C++ support),只需要勾選,系統會為我們預設新增一些配置
那麼如果是在舊專案上新增呢,這就需要我們手動配置一下了

Cmake配置檔案目錄.png
第一步,建立CMakeLists.txt檔案,注意,檔名必須這樣設定,大小寫區分,預設放在專案根目錄下,或者在其他位置,只需要你在build.gradle中配置即可
第二步,在專案根目錄的build.gradle檔案中配置
android { ...... defaultConfig { ...... // 指定要ndk需要相容的架構(這樣其他依賴包裡mips,x86,armeabi,arm-v8之類的so會被過濾掉) //例如如果的的so只支援arm平臺,那麼就像下邊這樣設定,如果還支援其他平臺則再後邊追加 ndk{ abiFilters 'armeabi' } } ...... externalNativeBuild{ //配置CMakeLists檔案地址 cmake{ path 'CMakeLists.txt' } } }
這裡貼出來我的CMakeLists.txt配置檔案
部分引數解析:
include_directories:表示引入專案so檔案所需的標頭檔案的路徑,在配置檔案中配置之後,編寫c程式碼的時候可以會在當前路徑下查詢標頭檔案,引入的路徑可以少些一些層級
find_library:引入內部已經支援的庫檔案
add_library:引入外部新增的庫檔案
cmake_minimum_required(VERSION 3.4.1) #引入標頭檔案位置 include_directories(src/main/cpp/include/ffmpeg) include_directories(src/main/cpp/include/owner) find_library( android-lib android ) find_library( log-lib log ) find_library( jnigraphics-lib jnigraphics ) #自己的庫 add_library( newffmpeg SHARED src/main/cpp/ffmpeg_player.c ) # 編解碼(最重要的庫) add_library( avcodec SHARED IMPORTED ) #指定編碼庫的位置 set_target_properties( avcodec PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavcodec-56.so ) #裝置資訊 add_library( avdevice SHARED IMPORTED ) #指定裝置資訊的位置 set_target_properties( avdevice PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavdevice-56.so ) #濾鏡特效處理庫 add_library( avfilter SHARED IMPORTED ) #指定濾鏡庫位置 set_target_properties( avfilter PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavfilter-5.so ) #封裝格式處理庫 add_library( avformat SHARED IMPORTED ) #指定格式庫路徑 set_target_properties( avformat PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavformat-56.so ) #工具庫(大部分庫都需要這個庫的支援) add_library( avutil SHARED IMPORTED ) #指定工具庫路徑 set_target_properties( avutil PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libavutil-54.so ) #後期處理 add_library( postproc SHARED IMPORTED ) #指定後期處理庫路徑 set_target_properties( postproc PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libpostproc-53.so ) #資料格式轉換庫 add_library( swresample SHARED IMPORTED ) #指定庫位置 set_target_properties( swresample PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libswresample-1.so ) #視訊畫素資料格式轉換 add_library( swscale SHARED IMPORTED ) #視訊畫素格式轉換庫位置 set_target_properties( swscale PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libswscale-3.so ) # 將預構建庫與本地庫相連 target_link_libraries( newffmpeg avcodec avdevice avfilter avformat avutil postproc swresample swscale ${android-lib} ${jnigraphics-lib} ${log-lib} )
so和C檔案目錄劃分
配置檔案搞好了,接下來就要正式的引入編譯好的ffmpeg so檔案了,如果不知道如何編譯,可以參考我之前的一片文章 09.阿里雲伺服器(Ubantu系統)配置ndk 編譯 ffmpeghttps://www.jianshu.com/p/826d2175f157 ,我們在專案main package下建立jniLibs資料夾,將編譯好的so放入這裡

so目錄.png
jniLibs目錄也是系統預設支援的,你當然可以設定其他名字,或者將目錄放在別的位置,但是要注意,如果你這樣做,一定要在build.gradle中進行指定,否則系統找不到這些檔案
細心的你可能發現在上邊的截圖上還有一個cpp的目錄,這個目錄是我們一般用來防止標頭檔案和c c++檔案的,系統預設不會建立這個目錄,也需要我們手動新增,除非你在建立專案的時候就添加了c++ support
這時候,基本上過程已經接近尾聲了,我們來看一下都做了什麼:
1.建立CMakeLists.txt指令碼檔案
2.在build.gradle中配置編譯選項
3.將so庫加入jniLibs資料夾,將.h 和 .c(c++)檔案放入cpp目錄
4.還有一步,我們要建立native方法,生成標頭檔案,載入so,
5.最後一步就是呼叫了,這一整個過程到此結束
package com.rzm.ffmpeglibrary; public class FFmpegUtils { static{ System.loadLibrary("newffmpeg"); } public native static void decode(String input,String output); }
#include "com_rzm_ffmpeglibrary_FFmpegUtils.h" /* * Class:com_rzm_ffmpeglibrary_FFmpegUtils * Method:decode * Signature: ()V */ JNIEXPORT void JNICALL Java_com_rzm_ffmpeglibrary_FFmpegUtils_decode (JNIEnv *env, jclass jclazz,jstring input,jstring output){ }
其實這裡還有很多細節可以多說一點,比如javah命令如何生成標頭檔案,javap命令如何獲取方法或者屬性的簽名,最重要的一點,ffmpeg從編寫指令碼檔案到開始編譯,這一整個過程如何走來,這些基本上在之前的文章中有提到,這裡就不再多說了。
總結一下,這裡提到的每個過程,CMakeLists.txt檔案的編寫才是重中之重,也正是我想說的,把指令碼中每一個命令搞清楚,在ndk開發的路上你就更近一步了。