AndroidStudio3.0使用Cmake進行JNI開發
前言
最近專案上做到了直播和音視訊的播放,這裡不可避免的涉及到了Android JNI開發。於是去市面上找到一本資料《音視訊開發進階指南》,我看出版時間很近是2017年12月。結果遇到了大坑,裡面的所有demo都是基於eclipse。包括作者提供的原始碼也是eclipse的工程。沒辦法只有自己填坑了,下面就是整個移植過程。由於初次JNI開發,整個過程也是跌跌撞撞的。
所有資料
首先認識一下Cmake
全部下載之後,我得出一些結論:
1.AS和Eclipse的c++程式碼存放位置不同,一個是jni資料夾,一個是cpp資料夾
2.AS使用的是CMakeList.txt檔案 而eclipse裡用的是.mk檔案
所以核心的不同就是這個CMakeList.txt 和.mk(makefile)檔案
這兩個檔案的功能一樣都是用於配置在不同平臺下的編譯
在androidstudio2.2之後,內建了Cmake編譯器。
關於Cmake的資料除了官網,其他地方都是零散的https://cmake.org/
裡面內容很多,但是沒必要全掌握。用到什麼再瞭解吧。
當然 如果你習慣了.mk檔案配置 AS也是支援的
這裡
新建AS工程匯入檔案
新建工程,記得勾選C++支援
然後就是一路next
完成新建專案之後,刪掉裡面的
jni方法 和C++ 檔案 以及CmakeList.txt檔案裡面的東西
現在變成了一個乾淨的JNI工程,這點很重要
把eclipse下的jni檔案拉入到AS中的cpp資料夾下面
刪掉.mk檔案 把java檔案拉入java目錄下面
編譯java native 方法的Cpp檔案
Mp3Encoder.java 裡面有三個native方法
public class Mp3Encoder {
public native int init(String pcmPath, int audioChannels, int bitRate, int sampleRate, String mp3Path);
public native void encode();
public native void destroy();
}
需要編寫對應的Cpp檔案,這裡我們可以用java -jni 命令生成也可以直接寫。
我的建議是直接寫,如果清楚對應的命名規則
跑到java 檔案目錄下面
javah -jni com.huruwo.androidmp3encoder.Mp3Encoder
注意記得加上包名,否則找不到類
生成了.h檔案,移到cpp目錄下面
然後開啟AudioEncoder.cpp 把對應的函式名替換成com_huruwo_androidmp3encoder_Mp3Encoder.h
裡的函式名
編寫CMakeLists.txt
接下來重點來了我將一行行講解下面的程式碼
cmake_minimum_required(VERSION 3.4.1)
首先設定Cmake的版本,這是每個CMakeLists.txt固定的欄位
include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/3rdparty/lame/include/lame
${CMAKE_SOURCE_DIR}/src/main/cpp/common)
新增依賴的標頭檔案目錄,這個要寫在前面
#新增靜態庫
add_library(
#庫名稱
lib-mp3
#型別 STATIC或者SHARE
STATIC
#檔案 靜態庫 檢視 set_target_properties
IMPORTED
)
set_target_properties(
#庫名 與前面的對應
lib-mp3
PROPERTIES IMPORTED_LOCATION
#檔案目錄
${CMAKE_SOURCE_DIR}/src/main/cpp/3rdparty/lame/lib/libmp3lame.a
)
新增靜態庫.a,注意兩個庫名要對應一樣
find_library(log-lib log)
用於尋找存在的庫(內建的log庫,輸出日誌資訊)
add_library(native-lib SHARED src/main/cpp/mp3_encoder.cpp src/main/cpp/AudioEncoder.cpp)
編譯本地的CPP 檔案 設定為native-lib 型別為SHARE型別 並且新增兩個檔案
最後使用target_link_libraries
把所有的庫連起來,注意順序
如果A依賴於B 那麼A寫在前面,所有我們整個順序倒過來加入
target_link_libraries( # Specifies the target library.
native-lib
lib-mp3
# Links the target library to the log library
# included in the NDK.
${log-lib} )
好了整個CmakeLists,txt寫完了
Sync一下,然後嘗試編譯一下。
成功執行,並且生成了.so檔案
這裡由於我設定了平臺是armeabi/armeabi-v7a 所以只有檔案下有東西
ndk {
abiFilters 'armeabi', 'armeabi-v7a'
}
完美
能用,跑兩步試試
我們把pcm檔案放入手機根目錄,在程式碼中指向這個檔案的目錄
同時配置一個生成的mp3目錄
跑起來,點選轉換按鈕
完美閃退
輸出日誌
04-01 23:57:56.218 6244-6273/? I/OpenGLRenderer: Initialized EGL, version 1.4
04-01 23:57:56.307 6244-6273/? W/MALI: glDrawArrays:714: [MALI] glDrawArrays takes more than 5ms here. Total elapse time(us): 25174
04-01 23:57:57.263 6244-6244/com.huruwo.androidmp3encoder I/Mp3Encoder: mp3Path is /storage/emulated/0/auto.mp3...
04-01 23:57:57.264 6244-6244/com.huruwo.androidmp3encoder A/libc: Fatal signal 4 (SIGILL), code 1, fault addr 0xef0d63c4 in tid 6244 (droidmp3encoder)
我觀察到輸出了日誌mp3Path is /storage/emulated/0/auto.mp3...
這行日誌是在AudioEncoder.cpp中的
Java_com_huruwo_androidmp3encoder_Mp3Encoder_init
函式
說明載入so檔案成功了,並且進入了函式 只是CPP程式碼出了問題
同時我搜索了Fatal signal 4 (SIGILL)
這幾個關鍵字
得到的答案也是關於NDK中cpp程式碼的異常導致的
但是這歌日誌完全看不出哪裡有問題,於是我開始斷點除錯cpp程式碼
發現程式總在env->ReleaseStringUTFChars(pcmPathParam, pcmPath);
這一行之後就會崩潰
媽的 我仔細的回想大學期間學過的C++程式碼,竟然發現這個函式沒有返回值
按道理這個不是void 宣告的函式,應該帶有返回值給java層
所以稍微修改一下
int result=encoder->Init(pcmPath, mp3Path, sampleRate, channels, bitRate);
return result;
好的,再跑一下試試
ok 這次沒有崩潰
但是沒有得到想要的
輸出日誌為
Encoder Initialized Failed..
繼續除錯,發現ret
引數得到的值為-1
這個值是從cpp程式碼返回來的,具體函式如下:
int ret = -1;
pcmFile = fopen(pcmFilePath, "rb");
if(pcmFile) {
mp3File = fopen(mp3FilePath, "wb");
if(mp3File) {
lameClient = lame_init();
lame_set_in_samplerate(lameClient, sampleRate);
lame_set_out_samplerate(lameClient, sampleRate);
lame_set_num_channels(lameClient, channels);
lame_set_brate(lameClient, bitRate / 1000);
lame_init_params(lameClient);
ret = 0;
}
}
return ret;
為-1 說明檔案沒有讀取成功
路徑反覆嘗試沒有錯誤,突然想到許可權問題
因為這裡不僅需要讀取檔案,還需要寫入檔案
但是原來的配置檔案只有 寫入檔案的許可權
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
所以應該加上 讀取檔案的許可權
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
最後完美執行,生成相應的mp3檔案
可以看到檔案確實壓縮了很多1.6MB–>148kb
點選播放 效果不錯。
總結
買書一定要謹慎,多看評論 包括豆瓣讀書 商品評價
否則遇上大坑只能自己填
相關推薦
AndroidStudio3.0使用Cmake進行JNI開發
前言 最近專案上做到了直播和音視訊的播放,這裡不可避免的涉及到了Android JNI開發。於是去市面上找到一本資料《音視訊開發進階指南》,我看出版時間很近是2017年12月。結果遇到了大坑,裡面的所有demo都是基於eclipse。包括作者提供的原始碼也是e
AndroidStudio3.0中JNI開發
1.什麼是JNI? JNI 是java native interface 的縮寫,如果想實現JAVA呼叫C、C++ ,那麼就需要利用JNI來實現,JNI可以使java和c、c++ 相互呼叫, JNI可以看做是翻譯,其實就是一套協議。 2.為什麼要用JNI?
手把手教你如何在Android下進行JNI開發(入門)
在進行Android開發的過程中,我們必定會遇到視訊影象處理、高強度密集運算、特殊演算法等場景,這時我們就不得不需要去接觸一些C/C++程式碼,進行JNI開發。下面我將從Android.mk和CMake這兩種方式教大家如何進行開發。文章結尾將給出演示的專案程式碼,如果你能耐心地仔細看完,相信你一定能掌握
如何在Windows環境下進行jni開發--NDK環境配置
ndk程式設計(native developer kit),關於jni(java native interface)這方面的使用,其實早在2014年的時候,就研究過這方面的知識,只是當時工作上用不到所以就沒對這方面進行一個彙總! 近期由於個人維護Android平
Android筆記之使用CMake進行JNI開發(Android Studio)
不知道有多少朋友像我一樣,被Android NDK開發的環境配置折騰到吐,然後放棄。從事Android工作幾年了,也不太願意接觸NDK開發。不過福利終於來了,新的AS中開始使用CMake開發jni,開發c跟開發java一樣簡單,你只需單純的執著於業務目標,跟折騰
利用IDEA進行JNI開發:生成Windows平臺下的dll檔案
由於站在巨人的肩膀上,學習過程中沒遇到什麼問題,所以此篇文章僅作為個人補充的內容。 總結下流程: 1.編寫包含本地方法的類 3.使用標頭檔案編寫.c原始檔 4.使用GCC或其他編譯工具(甚至你用VC,eclipse都行啊)將.c原始檔編譯連線為dll檔案。
在androidstudio中用cmake進行jni開發
首先在建立專案的時候勾選c++支援 在建立好的專案中stuido會自動給gradle配置cmake 接下來只需要在main下面的cpp目錄中編寫你想要的c程式碼,然後引用就可以 直接通過System.loadLibrary("nati
android studio 進行ndk/jni開發
一、前言:之前用eclipse開發ndk的時候大家是不是很痛苦,要做的事情很多: //NDK開發流程: 1、在java程式碼中 宣告本地方法(native) 2、通過javah工具完成jni樣式的標頭
jni開發中遇到的問題4:如何在jni中進行字串的合併
1:現狀: jni裡面沒有提供方法來直接執行字串的追加 2:思路: a--> 先將jstring變為c string b--> 再者使用c裡面的方法進行字串的追加(strncat)
使用bottle進行web開發(1):hello world
matches 動態 bsp allow 模塊 開發 code spec converter 為什麽使用bottle?因為簡單,就一個py文件,和其他模塊沒有依賴,3000多行代碼。 http://www.bottlepy.org/docs/dev/ 既然開始學習
使用bottle進行web開發(5):Generating Content
方便 () strings 系統 end byte 導致 res 名稱 在純粹的 WSGI中,你的應用能返回的數據類型是十分有限的,你必須返回可叠代的字符串,你能返回字符串是因為字符串是可以叠代的,但是這導致服務器將你的內容按一字符一字符的傳送,這個時候,Unicode 字
使用bottle進行web開發(4):HTTPError
instead bject hat red uil tle ott class not from bottle import error @error(404) def error404(error): return ‘Nothing here, sorry‘
01_c++下jni開發說明
img margin ati 函數 end create ica activit jni <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:to
讓你快速了解並掌握如何進行iOS開發技能
cor pat 單行 測試 col time reac 默認值 action 首先你要花點時間針對objective-c語言的學習;畢竟這個是iOS開發的基礎(你也可以嘗試用Swift,但此項目只是針對OC),編程套路其實都是差不多,多寫多想多實踐;關於環境的搭建就不
使用Android Studio進行NDK開發
ndk開發 開發 ews ret split c++基礎 ndk 給定 註意 Step1:創建native方法 很easy,僅僅須要給定義好的方法加上native關鍵詞就可以 註意:由於該方法的詳細實現是在c++中詳細實現的。所以相似於接口方法不
[Python] 利用Django進行Web開發
ons 條件 turn log har 包含 參數 ^c 檢測 第一步:下載並安裝django 首先,在Django官網上下載適合自己Python的Django版本,在安裝Django前首先確定你已成功安裝了python。 Windows系統下安裝Djang
使用VS2017進行Linux開發問題匯總
font home mmu 不能 解決 common soft dir family ①、重新安裝虛擬機開發環境後,生成項目,報錯如下: 1>------ 已啟動生成: 項目: asf_plugin_gd_trans, 配置: Debug x64 ------ 1
008_使用pyenv進行py開發環境管理
準備 upgrade 設計 喜歡 uninstall targe 額的 共存 打印 一、 安裝Python 絕大多數Python入門書籍,都會介紹如何安裝Python,然而,本書要介紹一種全新的安裝方式。使用pyenv來安裝並管理我們的環境。 pyenv簡介 由於Pytho
寫給使用Unity進行遊戲開發的建議
知新樹 寧金峰Unity是一款非常流行的遊戲開發軟件。它的功能令人印象深刻,也能夠適應不同的遊戲開發要求。遊戲開發人員可以使用Unity創建任意類型的遊戲,從世界級的RPG遊戲到最受歡迎的增強現實遊戲Pokemon Go。此外,許多初學者通用Unity來學習遊戲開發或遊戲編程。 Unity的真正影響更加多樣化
Github——利用 Github 進行團隊開發
origin pull 生產環境 沖突 git push 刪除 可能 基本 push github 提供了免費的遠程倉庫,私密倉庫需要花錢,當然可以選擇國內的碼雲 本地倉庫初始化 git init git add -A git commit -m ‘first com