1. 程式人生 > >AndroidStudio3.0使用Cmake進行JNI開發

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檔案

TIM截圖20180402174238.png

TIM圖片20180402174610.jpg

可以看到檔案確實壓縮了很多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