[Android開(kāi)發(fā)]利用Cmake在AndroidStudio來(lái)使用lame庫(kù)

之前項(xiàng)目需要將錄音的數(shù)據(jù)轉(zhuǎn)換成MP3文件,考慮一番后決定使用Lame庫(kù)進(jìn)行轉(zhuǎn)換。網(wǎng)上多采用ndk-build對(duì)其進(jìn)行構(gòu)建,但AndroidStudio支持Cmake有一段時(shí)間,此次使用Cmake來(lái)試試。

準(zhǔn)備:
1.在AndroidSudio上裝好Cmake和NDK 可以參考之前的文章
2.下載Lame的源碼 官方地址需要自備梯子

一、修改Lame的部分內(nèi)容
將Lame的源碼解壓后,把libmp3lame文件夾下除了.h和.c的文件都去掉,vector和i386文件夾也都去掉。并將在libmp3lame里剩下的文件,都復(fù)制到AS的cpp目錄下。同時(shí)還要將lame-3.99.5\include\lame.h這個(gè)頭文件也復(fù)制過(guò)去。到為了好管理,可以在cpp下新建一個(gè)文件夾把這些源碼也放在一起。


需要修改的部分:
1 、util.h中574行將里面的一行 extern ieee754_float32_t fast_log2(ieee754_float32_t x); 改為 extern float fast_log2(float x); 因?yàn)锳ndroid下并不支持該類(lèi)型

2、在id3tag.c和machine.h兩個(gè)文件里,將HAVE_STRCHR和HAVE_MEMCPY的ifdef結(jié)構(gòu)體注釋掉。

#ifdef STDC_HEADERS
# include <stdlib.h>
# include <string.h>
#else
/*# ifndef HAVE_STRCHR
#  define strchr index
#  define strrchr rindex
# endif*/
char   *strchr(), *strrchr();
/*# ifndef HAVE_MEMCPY
#  define memcpy(d, s, n) bcopy ((s), (d), (n))
#  define memmove(d, s, n) bcopy ((s), (d), (n))
# endif*/
#endif

3、fft.c中47行將vector/lame_intrin.h這個(gè)頭文件注釋了或者去掉

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "lame.h"
#include "machine.h"
#include "encoder.h"
#include "util.h"
#include "fft.h"

//#include "vector/lame_intrin.h"

4、set_get.h中24行將include <lame.h>改為include "lame.h"

#ifndef __SET_GET_H__
#define __SET_GET_H__

#include "lame.h"

二、編寫(xiě)CmakeList.txt
本例中l(wèi)ame的源碼和頭文件都放在了src/main/cpp/lamemp3這個(gè)文件夾下。在添加自定義庫(kù)既add_library時(shí),可以先指定一個(gè)目錄,然后將這個(gè)目錄傳入add_library中,避免一個(gè)個(gè)文件添加這么麻煩。另外lame本身并沒(méi)有jni的api,需要自己去編寫(xiě),本例中在SimpleLame.cpp中調(diào)用lame的api進(jìn)行簡(jiǎn)單的編碼轉(zhuǎn)換,讓PCM文件換為MP3文件。


cmake_minimum_required(VERSION 3.4.1)

#設(shè)置變量SRC_DIR為lamemp3的所在路徑
set(SRC_DIR src/main/cpp/lamemp3)

#指定頭文件所在,可以多次調(diào)用,指定多個(gè)路徑
include_directories(src/main/cpp/lamemp3)

#添加自自定義的so庫(kù)時(shí),有兩種方式,一種添加一個(gè)目錄,一種一個(gè)個(gè)文件添加

#設(shè)定一個(gè)目錄
aux_source_directory(src/main/cpp/lamemp3 SRC_LIST)

#將前面目錄下所有的文件都添加進(jìn)去
add_library(lamemp3 SHARED src/main/cpp/SimpleLame.cpp ${SRC_LIST})

#一個(gè)個(gè)文件的加
#add_library(lame-mp3
#            SHARED
#            ${SRC_DIR}/bitstream.c
#            ${SRC_DIR}/encoder.c
#            ${SRC_DIR}/fft.c
#            ${SRC_DIR}/gain_analysis.c
#            ${SRC_DIR}/id3tag.c
#            ${SRC_DIR}/lame.c
#            ${SRC_DIR}/mpglib_interface.c
#            ${SRC_DIR}/newmdct.c
#            ${SRC_DIR}/presets.c
#            ${SRC_DIR}/psymodel.c
#            ${SRC_DIR}/quantize.c
#            ${SRC_DIR}/quantize_pvt.c
#            ${SRC_DIR}/reservoir.c
#            ${SRC_DIR}/set_get.c
#            ${SRC_DIR}/tables.c
#            ${SRC_DIR}/takehiro.c
#            ${SRC_DIR}/util.c
#            ${SRC_DIR}/vbrquantize.c
#            ${SRC_DIR}/VbrTag.c
#            ${SRC_DIR}/version.c
#            )

find_library(log-lib log )

三、調(diào)用Lame的本地代碼,SimpleLame.cpp

#include <cwchar>
#include "SimpleLame.h"
#include "lamemp3/lame.h"

static lame_global_flags *glf = NULL;

void Java_com_clam314_lame_SimpleLame_close(JNIEnv *env, jclass type){
    lame_close(glf);
    glf = NULL;
}

jint Java_com_clam314_lame_SimpleLame_encode(JNIEnv *env, jclass type, jshortArray buffer_l_,
                                        jshortArray buffer_r_, jint samples, jbyteArray mp3buf_) {
    jshort *buffer_l = env->GetShortArrayElements(buffer_l_, NULL);
    jshort *buffer_r = env->GetShortArrayElements(buffer_r_, NULL);
    jbyte *mp3buf = env->GetByteArrayElements(mp3buf_, NULL);

    const jsize mp3buf_size = env->GetArrayLength(mp3buf_);

    int result =lame_encode_buffer(glf, buffer_l, buffer_r, samples, (u_char*)mp3buf, mp3buf_size);

    env->ReleaseShortArrayElements(buffer_l_, buffer_l, 0);
    env->ReleaseShortArrayElements(buffer_r_, buffer_r, 0);
    env->ReleaseByteArrayElements(mp3buf_, mp3buf, 0);

    return result;
}

jint Java_com_clam314_lame_SimpleLame_flush(JNIEnv *env, jclass type, jbyteArray mp3buf_) {
    jbyte *mp3buf = env->GetByteArrayElements(mp3buf_, NULL);

    const jsize  mp3buf_size = env->GetArrayLength(mp3buf_);

    int result = lame_encode_flush(glf, (u_char*)mp3buf, mp3buf_size);

    env->ReleaseByteArrayElements(mp3buf_, mp3buf, 0);

    return result;
}

void Java_com_clam314_lame_SimpleLame_init__IIIII(JNIEnv *env, jclass type, jint inSampleRate, jint outChannel,
                                             jint outSampleRate, jint outBitrate, jint quality) {
    if(glf != NULL){
        lame_close(glf);
        glf = NULL;
    }
    glf = lame_init();
    lame_set_in_samplerate(glf, inSampleRate);
    lame_set_num_channels(glf, outChannel);
    lame_set_out_samplerate(glf, outSampleRate);
    lame_set_brate(glf, outBitrate);
    lame_set_quality(glf, quality);
    lame_init_params(glf);
}

四、調(diào)用Lame對(duì)應(yīng)的Java代碼

public class SimpleLame {

    public native static void close();

    public native static int encode(short[] buffer_l, short[] buffer_r, int samples, byte[] mp3buf);

    public native static int flush(byte[] mp3buf);

    public native static void init(int inSampleRate, int outChannel, int outSampleRate, int outBitrate, int quality);

    public static void init(int inSampleRate, int outChannel, int outSampleRate, int outBitrate) {
        init(inSampleRate, outChannel, outSampleRate, outBitrate, 7);
    }
}

這里重點(diǎn)介紹Lame庫(kù)的移植,完整的實(shí)現(xiàn)錄音-轉(zhuǎn)碼-播放的代碼放到github上了
項(xiàng)目地址:https://github.com/clam314/LameMp3ForAndroid

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 貌似許多人都是從lame庫(kù)開(kāi)始入門(mén)Android NDK開(kāi)發(fā)的,在網(wǎng)上一搜一大堆詳細(xì)教程。本篇的亮點(diǎn)是采用Goog...
    Javine_Kuang閱讀 1,620評(píng)論 2 7
  • 1.安裝 $sudo apt-get install cmake 2.示例:簡(jiǎn)單的文件目錄 sample |—...
    荷包蛋醬閱讀 29,894評(píng)論 0 15
  • 在項(xiàng)目中要實(shí)裝lame的開(kāi)源庫(kù)實(shí)現(xiàn)錄音轉(zhuǎn)碼mp3的功能。期間遇到諸多問(wèn)題,度娘了N多博客,最終總結(jié)了接入了lame...
    hahafei閱讀 7,547評(píng)論 11 11
  • 繼承是OO語(yǔ)言中的一個(gè)最為人津津樂(lè)道的概念。許多OO語(yǔ)言都支持兩種繼承方式:接口繼承和實(shí)現(xiàn)繼承。接口繼承只繼承方法...
    frankisbaby閱讀 117評(píng)論 0 0
  • 今天看到一位朋友在朋友圈里發(fā)了一句成者為王敗者寇,本來(lái)還沒(méi)怎么上心,結(jié)果靜下心來(lái)這么一想,竟有醍醐灌頂之感。一直以...
    騷人擱筆費(fèi)評(píng)章閱讀 1,292評(píng)論 0 0

友情鏈接更多精彩內(nèi)容