日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java libmp3lame_录制MP3格式的音频( lame 库的编译及使用)

發布時間:2023/12/16 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java libmp3lame_录制MP3格式的音频( lame 库的编译及使用) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

眾多周知,mp3 是跨平臺性最好的音頻格式,由于采用了壓縮率更高的有損壓縮算法,文件大小是大約每分鐘1M,使其在網絡中傳輸更快,占用存儲空間也更少;與此同時,它的聲音質量也不錯,尤其是人聲(相聲、評書、脫口秀),當然追求無損音樂的除外。

Android 中沒有提供錄制 mp3 的 API,需要使用開源庫 lame,lame 是專門用于編碼 mp3 的輕量高效的 c 代碼庫。由于采用 c 語言編寫,故需要用到 jni。

下載lame庫

源碼導入

解壓下載的lame庫,把libmp3lame文件夾下后綴為.c .h的文件(不包括子文件夾i386和vector下的)復制到cpp/lame文件夾內,同時把include目錄下的lame.h也復制到cpp/lame文件夾內,此時 lame文件夾內包含42個文件。

images.png

修改庫文件

打開剛剛拷貝的lame庫文件,修改:

util.h 文件,把 570 行的兩處 ieee754_float32_t 改為 float 因為Android下并不支持該類型

set_get.h 文件,把頭部的 #include 改為 #include "lame.h"

fft.c 文件,刪除第47行 #include "vector/lame_intrin.h"

id3tag.c和machine.h兩個文件里,將HAVE_STRCHR和HAVE_MEMCPY的ifdef結構體刪除或者注釋

#ifdef STDC_HEADERS

# include

# include

#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

可參考以下完整修改文件

diff --git a/VbrTag.c b/VbrTag.c

index 5800a44..36ee7b6 100644

--- a/VbrTag.c

+++ b/VbrTag.c

@@ -26,6 +26,8 @@

# include

#endif

+#include

+#include

#include "lame.h"

#include "machine.h"

#include "encoder.h"

diff --git a/bitstream.c b/bitstream.c

index aa35915..a2fe294 100644

--- a/bitstream.c

+++ b/bitstream.c

@@ -29,6 +29,7 @@

#include

#include

+#include

#include "lame.h"

#include "machine.h"

diff --git a/encoder.c b/encoder.c

index 48f46c7..437067f 100644

--- a/encoder.c

+++ b/encoder.c

@@ -30,6 +30,7 @@

#endif

+#include

#include "lame.h"

#include "machine.h"

#include "encoder.h"

diff --git a/fft.c b/fft.c

index 4eea1ad..27febdb 100644

--- a/fft.c

+++ b/fft.c

@@ -44,7 +44,7 @@

#include "util.h"

--- a/fft.c

+++ b/fft.c

@@ -44,7 +44,7 @@

#include "util.h"

#include "fft.h"

-#include "vector/lame_intrin.h"

+//#include "vector/lame_intrin.h"

diff --git a/id3tag.c b/id3tag.c

index ac48510..8f148b8 100644

--- a/id3tag.c

+++ b/id3tag.c

@@ -41,17 +41,20 @@

# include

# include

#else

-# ifndef HAVE_STRCHR

-# define strchr index

-# define strrchr rindex

-# endif

+//# 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))

-# endif

+//# ifndef HAVE_MEMCPY

+//# define memcpy(d, s, n) bcopy ((s), (d), (n))

+//# endif

#endif

+#include

+#include

+#include

#include "lame.h"

#include "machine.h"

#include "encoder.h"

diff --git a/lame.c b/lame.c

index cb82225..299fd56 100644

--- a/lame.c

+++ b/lame.c

@@ -31,6 +31,8 @@

#endif

+#include

+#include

#include "lame.h"

#include "machine.h"

diff --git a/machine.h b/machine.h

index bf6fff2..c675c20 100644

--- a/machine.h

+++ b/machine.h

@@ -31,15 +31,15 @@

# include

# include

#else

-# ifndef HAVE_STRCHR

-# define strchr index

-# define strrchr rindex

-# endif

+//# 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

+//# ifndef HAVE_MEMCPY

+//# define memcpy(d, s, n) bcopy ((s), (d), (n))

+//# define memmove(d, s, n) bcopy ((s), (d), (n))

+//# endif

#endif

#if defined(__riscos__) && defined(FPA10)

diff --git a/newmdct.c b/newmdct.c

index 596cac9..ac98abd 100644

--- a/newmdct.c

+++ b/newmdct.c

@@ -30,6 +30,7 @@

# include

#endif

+#include

#include "lame.h"

#include "machine.h"

#include "encoder.h"

diff --git a/psymodel.c b/psymodel.c

index 60076ee..1393c2a 100644

--- a/psymodel.c

+++ b/psymodel.c

@@ -145,7 +145,8 @@ blocktype_d[2] block type to use for previous granule

#endif

#include

-

+#include

+#include

#include "lame.h"

#include "machine.h"

#include "encoder.h"

diff --git a/quantize.c b/quantize.c

index 9ba9c16..2906c00 100644

--- a/quantize.c

+++ b/quantize.c

@@ -28,6 +28,8 @@

# include

#endif

+#include

+#include

#include "lame.h"

#include "machine.h"

#include "encoder.h"

diff --git a/quantize_pvt.c b/quantize_pvt.c

:

#endif

#include

-

+#include

+#include

#include "lame.h"

#include "machine.h"

#include "encoder.h"

diff --git a/quantize.c b/quantize.c

index 9ba9c16..2906c00 100644

--- a/quantize.c

+++ b/quantize.c

@@ -28,6 +28,8 @@

# include

#endif

+#include

+#include

#include "lame.h"

#include "machine.h"

#include "encoder.h"

diff --git a/quantize_pvt.c b/quantize_pvt.c

index d8d6447..3cd9966 100644

--- a/quantize_pvt.c

+++ b/quantize_pvt.c

@@ -36,6 +36,7 @@

#include "reservoir.h"

#include "lame-analysis.h"

#include

+#include

#define NSATHSCALE 100 /* Assuming dynamic range=96dB, this value should be 92 */

diff --git a/set_get.h b/set_get.h

index 37e4bcd..99ab73c 100644

--- a/set_get.h

+++ b/set_get.h

@@ -21,7 +21,7 @@

#ifndef __SET_GET_H__

#define __SET_GET_H__

-#include

+#include "lame.h"

#if defined(__cplusplus)

extern "C" {

diff --git a/takehiro.c b/takehiro.c

index 67aba1b..ca02f98 100644

--- a/takehiro.c

+++ b/takehiro.c

@@ -27,6 +27,7 @@

#endif

+#include

#include "lame.h"

#include "machine.h"

#include "encoder.h"

diff --git a/util.c b/util.c

index 43b457c..e9255fe 100644

--- a/util.c

+++ b/util.c

@@ -27,6 +27,7 @@

#endif

#include

+#include

#include "lame.h"

#include "machine.h"

#include "encoder.h"

diff --git a/util.h b/util.h

index 13f0cd4..b6bf306 100644

--- a/util.h

+++ b/util.h

@@ -567,7 +567,7 @@ extern "C" {

/* log/log10 approximations */

extern void init_log_table(void);

- extern ieee754_float32_t fast_log2(ieee754_float32_t x);

+ extern float fast_log2(float x);

int isResamplingNecessary(SessionConfig_t const* cfg);

diff --git a/vbrquantize.c b/vbrquantize.c

index 0f703b7..60834d3 100644

--- a/vbrquantize.c

+++ b/vbrquantize.c

@@ -27,6 +27,8 @@

#endif

+#include

+#include

#include "lame.h"

#include "machine.h"

#include "encoder.h"

編寫CmakeList.txt

cmake_minimum_required(VERSION 3.6.0)

set(CURRENT_DIR ${CMAKE_SOURCE_DIR})

message("CURRENT_DIR:" ${CMAKE_SOURCE_DIR})

include_directories(${CMAKE_SOURCE_DIR}src/main/cpp/lame)

set(LAME_DIR src/main/cpp/lame)

message("LAME_DIR:" ${LAME_DIR})

aux_source_directory(src/main/cpp/lame SRC_LIST)

add_library(mp3lame

SHARED

src/main/cpp/MP3Recorder.c

${SRC_LIST})

#add_library(mp3lame

# SHARED

# src/main/cpp/MP3Recorder.c

# src/main/cpp/lame/bitstream.c

# src/main/cpp/lame/fft.c

# src/main/cpp/lame/id3tag.c

# src/main/cpp/lame/mpglib_interface.c

# src/main/cpp/lame/presets.c

# src/main/cpp/lame/quantize.c

# src/main/cpp/lame/reservoir.c

# src/main/cpp/lame/tables.c

# src/main/cpp/lame/util.c

# src/main/cpp/lame/VbrTag.c

# src/main/cpp/lame/encoder.c

# src/main/cpp/lame/gain_analysis.c

# src/main/cpp/lame/lame.c

# src/main/cpp/lame/newmdct.c

# src/main/cpp/lame/psymodel.c

# src/main/cpp/lame/quantize_pvt.c

# src/main/cpp/lame/set_get.c

# src/main/cpp/lame/takehiro.c

# src/main/cpp/lame/vbrquantize.c

# src/main/cpp/lame/version.c)

find_library( # Sets the name of the path variable.

log-lib

log)

target_link_libraries(mp3lame

${log-lib})

編寫 java 類和 c 文件

public class MP3Recorder {

static {

System.loadLibrary("mp3lame");

}

/**

* 初始化 lame編碼器

*

* @param inSampleRate

* 輸入采樣率

* @param outChannel

* 聲道數

* @param outSampleRate

* 輸出采樣率

* @param outBitrate

* 比特率(kbps)

* @param quality

* 0~9,0最好

*/

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

/**

* 編碼,把 AudioRecord 錄制的 PCM 數據轉換成 mp3 格式

*

* @param buffer_l

* 左聲道輸入數據

* @param buffer_r

* 右聲道輸入數據

* @param samples

* 輸入數據的size

* @param mp3buf

* 輸出數據

* @return

* 輸出到mp3buf的byte數量

*/

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

/**

* 刷寫

*

* @param mp3buf

* mp3數據緩存區

* @return

* 返回刷寫的數量

*/

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

/**

* 關閉 lame 編碼器,釋放資源

*/

public static native void close();

}

生成.h文件

編寫MP3Recorder.c

#include "lame/lame.h"

#include "MP3Recorder.h"

static lame_global_flags *glf = NULL;

/*

* Class: com_android_liblame_MP3Recorder

* Method: init

* Signature: (IIIII)V

*/

JNIEXPORT void JNICALL Java_com_android_liblame_MP3Recorder_init

(JNIEnv *env, jclass instance, 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);

}

/*

* Class: com_android_liblame_MP3Recorder

* Method: encode

* Signature: ([S[SI[B)I

*/

JNIEXPORT jint JNICALL Java_com_android_liblame_MP3Recorder_encode

(JNIEnv *env, jclass instance, jshortArray buffer_l, jshortArray buffer_r, jint samples,

jbyteArray mp3buf) {

jshort *j_buffer_l = (*env)->GetShortArrayElements(env, buffer_l, NULL);

jshort *j_buffer_r = (*env)->GetShortArrayElements(env, buffer_r, NULL);

const jsize mp3buf_size = (*env)->GetArrayLength(env, mp3buf);

jbyte *j_mp3buf = (*env)->GetByteArrayElements(env, mp3buf, NULL);

int result = lame_encode_buffer(glf, j_buffer_l, j_buffer_r,

samples, j_mp3buf, mp3buf_size);

(*env)->ReleaseShortArrayElements(env, buffer_l, j_buffer_l, 0);

(*env)->ReleaseShortArrayElements(env, buffer_r, j_buffer_r, 0);

(*env)->ReleaseByteArrayElements(env, mp3buf, j_mp3buf, 0);

return result;

}

/*

* Class: com_android_liblame_MP3Recorder

* Method: flush

* Signature: ([B)I

*/

JNIEXPORT jint JNICALL Java_com_android_liblame_MP3Recorder_flush

(JNIEnv *env, jclass instance, jbyteArray mp3buf) {

const jsize mp3buf_size = (*env)->GetArrayLength(env, mp3buf);

jbyte *j_mp3buf = (*env)->GetByteArrayElements(env, mp3buf, NULL);

int result = lame_encode_flush(glf, j_mp3buf, mp3buf_size);

(*env)->ReleaseByteArrayElements(env, mp3buf, j_mp3buf, 0);

return result;

}

/*

* Class: com_android_liblame_MP3Recorder

* Method: close

* Signature: ()V

*/

JNIEXPORT void JNICALL Java_com_android_liblame_MP3Recorder_close

(JNIEnv *env, jclass instance) {

lame_close(glf);

glf = NULL;

}

配置build.gradle

android {

....

...

..

.

//*

externalNativeBuild {

cmake {

path "CMakeLists.txt"

}

}

}

點一下小錘子 :hammer: MakeProject。

編譯生成 so庫。

錄制MP3格式音頻

// 錄音狀態

private boolean isRecording;

//開始錄音

private void record() {

new Thread() {

@Override

public void run() {

// 音源

int audioSource = MediaRecorder.AudioSource.MIC;

// 采樣率

int sampleRate = 44100;

// 聲道

int channelConfig = AudioFormat.CHANNEL_IN_MONO;//單聲道

// 采樣位數

int audioFormat = AudioFormat.ENCODING_PCM_16BIT;

// 錄音緩存區大小

int bufferSizeInBytes;

// 文件輸出流

FileOutputStream fos;

// 錄音最小緩存大小

bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);

AudioRecord audioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, audioFormat, bufferSizeInBytes);

try {

fos = new FileOutputStream(getExternalCacheDir() + "/demo.mp3");

MP3Recorder.init(sampleRate, 2, sampleRate, 128, 5);

short[] buffer = new short[bufferSizeInBytes];

byte[] mp3buffer = new byte[(int) (7200 + buffer.length * 1.25)];

audioRecord.startRecording();

isRecording = true;

while (isRecording && audioRecord.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {

int readSize = audioRecord.read(buffer, 0, bufferSizeInBytes);

if (readSize > 0) {

int encodeSize = MP3Recorder.encode(buffer, buffer, readSize, mp3buffer);

if (encodeSize > 0) {

try {

fos.write(mp3buffer, 0, encodeSize);

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

int flushSize = MP3Recorder.flush(mp3buffer);

if (flushSize > 0) {

try {

fos.write(mp3buffer, 0, flushSize);

} catch (IOException e) {

e.printStackTrace();

}

}

try {

fos.close();

} catch (IOException e) {

e.printStackTrace();

}

audioRecord.stop();

audioRecord.release();

MP3Recorder.close();

} catch (FileNotFoundException e) {

e.printStackTrace();

}

}

}.start();

}

// 停止錄音

private void stop() {

isRecording = false;

}

在 AndroidManifest 配置文件中添加錄音權限:

Android 6.0 以上還要動態獲取權限。

Reference

總結

以上是生活随笔為你收集整理的java libmp3lame_录制MP3格式的音频( lame 库的编译及使用)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。