一、交叉编译LAME库

LAME是一种非常优秀的MP3编码引擎,在业界,转码成MP3格式的音频文件时,最常用的编码器就是LAME库。

1. 下载LAME库源码

https://sourceforge.net/projects/lame/files/lame/
进入LAME官网下载LAME源码,我选择最新版本:3.100

2. 配置交叉编译环境

在编译LAME之前,我们需要先配置交叉编译环境。

Android NDK附带了交叉工具链,具体参考这篇文章:https://developer.android.com/ndk/guides/other_build_systems?hl=zh-cn

我的NDK路径为:/home/lorien/Android/Sdk/ndk/22.1.7171670/toolchains/llvm/prebuilt/linux-x86_64/bin

3. 配置、编译、安装LAME

首先我们需要编译使用的一些环境变量:

#!/bin/bashexport TOOLCHAIN=/home/lorien/Android/Sdk/ndk/22.1.7171670/toolchains/llvm/prebuilt/linux-x86_64
export TARGET=aarch64-linux-android
export API=21
export AR=$TOOLCHAIN/bin/llvm-ar
export CC=$TOOLCHAIN/bin/$TARGET$API-clang
export AS=$CC
export CXX=$TOOLCHAIN/bin/$TARGET$API-clang++
export LD=$TOOLCHAIN/bin/ld
export RANLIB=$TOOLCHAIN/bin/llvm-ranlib
export STRIP=$TOOLCHAIN/bin/llvm-stripexport CFLAGS="-fPIC"

接下来解压的LAME源码:lame-3.100.tar.gz,解压后进入源码根目录:/lame-3.100

配置:

./configure --host=arm-linux --disable-shared --disable-frontend --enable-static --prefix=/Users/zhanghao43/Desktop/lame/arm64-v8a

编译:

make clean
make -j4

安装:

make install

安装完成后,生成的头文件和库文件,就会在prefix指定的路径下面,即:/Users/zhanghao43/Desktop/lame/arm64-v8a

在生成的文件中,接下来需要使用的文件是:

  • 头文件:/Users/zhanghao43/Desktop/lame/arm64-v8a/include/lame/lame.h
  • 库文件:/Users/zhanghao43/Desktop/lame/arm64-v8a/lib/lame/libmp3lame.a

至此,LAME库交叉编译完成。

二、创建Android Native项目使用LAME库

下面我们使用LAME库创建一个Android Demo项目,完成PCM音频的录制以及PCM文件转MP3的功能
我们需要创建Android Natvie项目。

1. 配置工程

我们先把编译LAME库生成的头文件和库文件放到项目中,路径如下图:

然后,我们修改下CMakeLists.txt,让CMake在编译、链接时,找到LAME头文件和库文件。CMakeLists.txt文件内容如下:

cmake_minimum_required(VERSION 3.10.2)# Declares and names the project.project("lame")include_directories(${CMAKE_SOURCE_DIR}/include/lame)add_library( # Sets the name of the library.native-lib# Sets the library as a shared library.SHARED# Provides a relative path to your source file(s).native-lib.cpp mp3_encoder.cpp)add_library(mp3lame STATIC IMPORTED)
set_target_properties(mp3lame PROPERTIES IMPORTED_LOCATION${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libmp3lame.a)find_library( # Sets the name of the path variable.log-lib# Specifies the name of the NDK library that# you want CMake to locate.log )target_link_libraries(native-libmp3lame)

2. C++代码

接下来,可以写代码了。首先看一下mp3_encoder.h, mp3_encoder.cpp

#ifndef LAME_MP3ENCODER_H
#define LAME_MP3ENCODER_H
#include <stdio.h>
#include "lame.h"class Mp3Encoder {private:FILE* pcmFile;FILE* mp3File;lame_t lameClient;public:Mp3Encoder();~Mp3Encoder();int Init(const char* pcmFilePath, const char* mp3FilePath, int sampleRate, int channels, int bitRate);void Encode();void Destroy();
};#endif //LAME_MP3ENCODER_H
#include "mp3_encoder.h"
#include "lame.h"Mp3Encoder::Mp3Encoder() {}int Mp3Encoder::Init(const char* pcmFilePath, const char* mp3FilePath, int sampleRate, int channels, int bitRate) {int ret = -1;pcmFile = fopen(pcmFilePath, "rb");if (pcmFile) {mp3File = fopen(mp3FilePath, "wb");if (mp3File) {lameClient = lame_init();// in 采样率lame_set_in_samplerate(lameClient, sampleRate);// out 采样率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;
}void Mp3Encoder::Encode() {int bufferSize = 1024 * 256;short *buffer = new short[bufferSize / 2];short *leftBuffer = new short[bufferSize / 4];short *rightBuffer = new short[bufferSize / 4];unsigned char* mp3_buffer = new unsigned char[bufferSize];size_t readBufferSize = 0;while ((readBufferSize = fread(buffer, 2, bufferSize / 2, pcmFile)) > 0) {for (int i = 0; i < readBufferSize; i++) {if (i % 2 == 0) {leftBuffer[i / 2] = buffer[i];} else {rightBuffer[i / 2] = buffer[i];}}size_t wroteSize = lame_encode_buffer(lameClient, (short int *) leftBuffer, (short int *) rightBuffer, (int)(readBufferSize / 2), mp3_buffer, bufferSize);fwrite(mp3_buffer, 1, wroteSize, mp3File);}delete [] buffer;delete [] leftBuffer;delete [] rightBuffer;delete [] mp3_buffer;
}void Mp3Encoder::Destroy() {if (pcmFile) {fclose(pcmFile);}if (mp3File) {fclose(mp3File);lame_close(lameClient);}
}

然后我们看一下native-lib.cpp中的JNI方法:

Mp3Encoder *encoder;extern "C" JNIEXPORT jint JNICALL
Java_com_baidu_lame_MainActivity_pcmToMp3JNI(JNIEnv *env,jobject,jstring pcm_path,jstring mp3_path,jint sample_rate,jint channel,jint bit_rate) {const char *pcmPath = env->GetStringUTFChars(pcm_path, NULL);const char *mp3Path = env->GetStringUTFChars(mp3_path, NULL);encoder = new Mp3Encoder();encoder->Init(pcmPath, mp3Path, sample_rate, channel, bit_rate);encoder->Encode();env->ReleaseStringUTFChars(pcm_path, pcmPath);env->ReleaseStringUTFChars(mp3_path, mp3Path);return 0;
}

3. Java代码

先贴一下MainAcgtivity的XML文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="开始录制pcm"android:onClick="startRecordPcm"/><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="停止录制pcm"android:onClick="stopRecordPcm"/><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="pcm转mp3"android:onClick="pcm2mp3"/></LinearLayout>

MainActivity.kt

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)}external fun stringFromJNI(): Stringexternal fun pcmToMp3JNI(pcmPath: String, mp3Path: String,sampleRate: Int, channel: Int, bitRate: Int): Intcompanion object {init {System.loadLibrary("native-lib")}}private lateinit var audioRecord: AudioRecordprivate var pcmFilePath: String = ""private var buffersize = 1024private var isRecord = false/*** 调用Native代码完成PCM文件转成MP3*/fun pcm2mp3(view: View) {val pcmPath = getPCMFile().absolutePathval mp3Path = getMP3File().absolutePathval sampleRate = 44100val channel = 2val bitRate = 64000val ret = pcmToMp3JNI(pcmPath, mp3Path, sampleRate, channel, bitRate)Toast.makeText(this, "$ret", Toast.LENGTH_SHORT).show()}/*** 开始录制PCM音频文件*/@SuppressLint("MissingPermission")fun startRecordPcm(view: View) {val frequency = 44100val channelConfig = AudioFormat.CHANNEL_IN_STEREOval audioEncoding = AudioFormat.ENCODING_PCM_16BITbuffersize = AudioRecord.getMinBufferSize(frequency, channelConfig, audioEncoding)audioRecord = AudioRecord(MediaRecorder.AudioSource.MIC,frequency,channelConfig,audioEncoding,buffersize)pcmFilePath = getPCMFile().absolutePathisRecord = trueRecordThread().start()}/*** 结束录制PCM音频文件*/fun stopRecordPcm(view: View) {isRecord = false}private fun getPCMFile(): File {val root = getExternalFilesDir(null)val csvDir = File(root, "/audio/")if (!csvDir.exists()) {// 创建csv 目录csvDir.mkdir()}return File(csvDir, "sing.pcm")}private fun getMP3File(): File {val root = getExternalFilesDir(null)val csvDir = File(root, "/audio/")if (!csvDir.exists()) {// 创建csv 目录csvDir.mkdir()}return File(csvDir, "sing.mp3")}/*** 录制PCM音频线程*/inner class RecordThread : Thread() {override fun run() {audioRecord.startRecording()var fos: FileOutputStream? = nulltry {Log.d(TAG, "pcm文件:$pcmFilePath")fos = FileOutputStream(pcmFilePath)val bytes = ByteArray(buffersize)while (isRecord) {audioRecord.read(bytes, 0, bytes.size)fos.write(bytes, 0, bytes.size)fos.flush()}Log.d(TAG, "停止录制")audioRecord.stop()fos.flush()} catch (e: Exception) {Log.d(TAG, "exception: $e")} finally {if (fos != null) {try {fos.close()} catch (e: Exception) {}}}}}
}

最后,权限:

<!--录音-->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!--读取SD卡-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

代码中,没有动态申请权限,APP装上后,需要再到设置页面给APP开下对应权限才能录制音频。

OK,本文到这就结束了,感谢大家阅读。

Android集成LAME库,实现pcm转mp3相关推荐

  1. android lame音频转换,音视频开发02--使用LAME库转换pcm文件到mp3

    android 使用 AudioRecord 对麦克风进行录音得到的是 pcm 格式的原始音频数据,pcm文件是不能用来播放的,需要进行编码压缩. LAME是目前非常优秀的一种MP3编码引擎,在业界, ...

  2. android 集成第三方库和程序

    1.集成静态库 1: LOCAL_PATH := $(call my-dir) 2: include $(CLEAR_VARS) 3: 4: LOCAL_PREBUILT_LIBS := libA.a ...

  3. android如何编译lame,Android 编译 Lame 库心路历程

    编译脚本 lame 版本 下载完成后 编译 生成 include lib 两个文件夹 直接拷贝到 lib 目录下 集成 然后 CMakeList 里面添加头文件路径 不做这一步 后面无法在 C++文件 ...

  4. android集成第三方库

    1.把文件复制到app同级别libs里. 2.在appbuild里加入 sourceSets {main {jniLibs.srcDirs = ['libs']}} 告诉编译器库在哪个文件夹下. 3. ...

  5. 使用Lame库实现wav、pcm转mp3

    文章目录 前言 一.Lame库是什么? 二.使用步骤 0.创建native项目 1.下载Lame库 2.pcm转MP3 3.wav转MP3 4.native方法如下 三.注意 总结 前言 因为使用an ...

  6. Android直播开发之旅(4):MP3编码格式分析与lame库编译封装

    转载请声明出处:http://blog.csdn.net/andrexpert/article/77683776 一.Mp3编码格式分析 MP3,全称MPEG Audio Layer3,是一种高效的计 ...

  7. ffmpeg开发之旅(4):MP3编码格式分析与lame库编译封装

    ffmpeg开发之旅(4):MP3编码格式分析与lame库编译封装 原文链接:http://blog.csdn.net/andrexpert/article/77683776 一.Mp3编码格式分析 ...

  8. Android使用LAME将pcm文件转mp3文件

    Android使用LAME将pcm格式转mp3格式 lame介绍:LAME是一款开源的MP3编码器,被认为是中高比特率和VBR的最佳MP3编码器,质量和速度方面的改进仍在继续,可能使LAME成为仍在积 ...

  9. Android使用lame将PCM文件转码为MP3文件

    Android使用lame将PCM文件转码为MP3文件 1. 软件版本 Android Studio版本:4.2 lame版本:3.100 编译参考:centos7使用ndk编译lame 2. 项目配 ...

  10. Android音视频开发入门(5)使用LAME编码一个PCM文件,为了跳槽强刷1000道Android真题

    无论是自行安装PC上的编译器,还是下载其他平台的交叉编译链,它们都会提供下面几个工具: CC 编译器,对C源文件进行编译处理,生成汇编文件 AS 将汇编文件生成目标文件 AR 打包器,用于库操作 LD ...

最新文章

  1. 清华大佬告诉史上最全的Java进阶书籍推荐面南背北
  2. 二叉树的建造、递归与非递归遍历
  3. 017——VUE中v-fo指令的使用方法
  4. JavaWeb学习笔记——XML简介
  5. 2021-03-29 自动控制-滑模控制 Simulink仿真
  6. 从淘特升级,看电商特别模式的特别价值
  7. matplotlib,numpy自己动手安装
  8. 开源游戏机java模拟器_开源一个Flutter编写的完整终端模拟器
  9. scrollview下拉刷新_SwiftUI之View Tree 实战3(下拉刷新)
  10. 推断单向链表中是否有环和查找环的入口
  11. 【Python3网络爬虫开发实战】1.7.2-mitmproxy的安装
  12. springmvc 优点_深入整合SSM框架引发底层原理——SpringMVC
  13. 刘强东成京东数科二股东;高通再诉苹果;金立否认裁定破产 | 极客头条
  14. ZYNQ 调试遇到的种种问题汇总[转帖]
  15. DOS批处理中对含有特殊字符的文件名的处理方法
  16. VGS--网络三维互动软件技术
  17. printJs 打印HTML 去掉页眉页脚
  18. java满天星星代码_java实现满天星swingawt
  19. 3A(AF AE AWB)综述
  20. 解决ios系统下微信页面无法播放背景音乐的问题

热门文章

  1. 3种竞争力分析的简单途径
  2. H3C S5820x 期望风道方向的注意事项
  3. 全国计算机等级考试报名支付不了,23日起,全国计算机等级考试开始网上报名...
  4. 1's Complement和2's Complement的区别
  5. 李宏毅2022机器学习hw5
  6. ckplayer 播放视频
  7. c语言调用even函数,定义一个判断奇偶数的函数even(int n),当n为偶数时返回1,否则返回0,并实现对其调用。...
  8. 独孤求败-小滴云架构大课十八式【xiaoecf】
  9. RHCE——控制服务和守护进程
  10. 库房--库存信息增加导出Excel表格功能