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

2023-10-24 08:32
文章标签 android 使用 pcm mp3 lame

本文主要是介绍Android使用LAME将pcm文件转mp3文件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Android使用LAME将pcm格式转mp3格式

lame介绍:LAME是一款开源的MP3编码器,被认为是中高比特率和VBR的最佳MP3编码器,质量和速度方面的改进仍在继续,可能使LAME成为仍在积极开发的唯一MP3编码器。使用lame进行mp3编码,需要了解一些NDK相关的知识,比如jni和cmake。

准备工作:

  • 下载lame源码:https://lame.sourceforge.io/ 直接下载最新版本,本文使用的是3.100版本
  • android studio新建一个c++ support项目

集成lame源码

在cpp目录下,新建一个文件夹lamemp3,将下载的的源码文件中的\lame-3.100\libmp3lame文件夹下的所有.c和.h文件拷贝到lamemp3下并将\lame-3.100\include下的lame.h也拷贝进去,到这里,lame的源码都已经拷贝完成了,接下来,需要修改部分源码内容以及gradle配置参数。

1)删除fft.c文件的47行的”include “vector/lame_intrin.h”“

2)修改set_get.h文件的24行的#include“lame.h”

3)将util.h文件的574行的”extern ieee754_float32_t fast_log2(ieee754_float32_t x);”
替换为 “extern float fast_log2(float x);”

需要修改app 下的build.gradle文件

android {
...defaultConfig {...externalNativeBuild{cmake{cFlags "-DSTDC_HEADERS"}}}
}

接下来,我们编辑cmake,编辑好以后,点击android studio的build下的refresh linked c++ project,关于cmake部分,看cmake文件注释部分,cmake编写方式不局限一种,取决于你对cmake相关方法的了解

# Sets the minimum version of CMake required to build the native library.
#设置构建本地库所需的最低cmake版本
cmake_minimum_required(VERSION 3.4.1)
#设置库文件导出目录
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lameLibs/${ANDROID_ABI})
#批量导入c文件和cpp文件
file(GLOB lame lamemp3/*.c)
file(GLOB lame2 lamemp3/*.cpp)
#批量导入头文件
include_directories(${CMAKE_CURRENT_LIST_DIR}/lamemp3)
# 创建和给一个库命名,可以设置为静态库
# 或动态库,并且提供它源码的相关路径
# 你可以定义多个库,然后cmake为你构建他们
# gradle会自动打包共享库到你的apk中
add_library( # Sets the name of the library.native-lib# Sets the library as a shared library.SHARED# 导入所有源文件native-lib.cpp${lame}${lame2})#所有指定的预构建库,并将路径定义为变量,用于后面引入
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)#指令cmake需要链接到的库
target_link_libraries(#指定目标librarynative-lib#链接目标库到log库${log-lib})

编写MP3转换的c++实现,

在cpp/lamemp3文件夹下载新建pcm2pm3.cpp和pcm2pm3.h文件,这里贴出实现部分,完成代码参考项目源码

//初始化lame
int pcm2mp3::init(const char *pcm_path, const char *mp3_path, int sample_rate, int channel,int bitRate) {int result=-1;pcm_file=fopen(pcm_path,"rb");if(pcm_file!= NULL){mp3_file=fopen(mp3_path,"wb");if (mp3_file!= NULL){//开始初始化lame_client=lame_init();lame_set_in_samplerate(lame_client,sample_rate);lame_set_out_samplerate(lame_client,sample_rate);lame_set_num_channels(lame_client,channel);lame_set_brate(lame_client,bitRate);lame_set_quality(lame_client,2);lame_init_params(lame_client);result=0;}}return result;
}
//pcm文件转mp3文件
void pcm2mp3::pcm_to_mp3() {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, pcm_file)) > 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(lame_client, (short int *) leftBuffer, (short int *) rightBuffer, (int)(readBufferSize / 2), mp3_buffer, bufferSize);fwrite(mp3_buffer, 1, wroteSize, mp3_file);}delete [] buffer;delete [] leftBuffer;delete [] rightBuffer;delete [] mp3_buffer;}

接下来就是编写jni调用c++方法,定义了三个native方法,一个获取版本号用于测试lame加载是否成功,pcmTomp3进行文件转换,destroy进行相关对象的释放

public class LameJni {static {System.loadLibrary("native-lib");}public native String getVersion();//初始化lamepublic native int pcmTomp3(String pcmPath,String mp3Path,int sampleRate, int channel,  int bitRate);public native void destroy();}

然后是对native方法的实现,这里只贴出转换的实现,关于jni的命名规则以及类型转换规则,这里不多赘述,查看jni相关资料即可

pcm2mp3 *mp3_encoder;
extern "C"
JNIEXPORT int JNICALL
Java_com_david_sampling_util_LameJni_pcmTomp3(JNIEnv *env, jclass clazz, jstring pcm_path,jstring mp3_path, jint sample_rate, jint channel,jint bit_rate) {int result=-1;const char *pcm_path_=env->GetStringUTFChars(pcm_path,0);const char *mp3_path_=env->GetStringUTFChars(mp3_path,0);mp3_encoder=new pcm2mp3();mp3_encoder->init(pcm_path_,mp3_path_,sample_rate,channel,bit_rate);mp3_encoder->pcm_to_mp3();env->ReleaseStringUTFChars(pcm_path,pcm_path_);env->ReleaseStringUTFChars(mp3_path,mp3_path_);return result;
}

然后java层通过jni调用即可实现mp3文件的编码

//注:本例经过尝试,发现如果采样率不缩小,那么声音会变快,原因还未找到
lameJni.pcmTomp3(pcmFile.getAbsolutePath(),mp3File.getAbsolutePath(),mSampleRate/2,mChannel==AudioFormat.CHANNEL_IN_MONO?1:2,128);

以上,即可将pcm转换为mp3,关于pcm的获取,可以参考上一篇:https://blog.csdn.net/s591628545/article/details/104525958

项目地址:https://github.com/kingdavidsun/AudioSampling.git

这篇关于Android使用LAME将pcm文件转mp3文件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/273965

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

k8s按需创建PV和使用PVC详解

《k8s按需创建PV和使用PVC详解》Kubernetes中,PV和PVC用于管理持久存储,StorageClass实现动态PV分配,PVC声明存储需求并绑定PV,通过kubectl验证状态,注意回收... 目录1.按需创建 PV(使用 StorageClass)创建 StorageClass2.创建 PV

Redis 基本数据类型和使用详解

《Redis基本数据类型和使用详解》String是Redis最基本的数据类型,一个键对应一个值,它的功能十分强大,可以存储字符串、整数、浮点数等多种数据格式,本文给大家介绍Redis基本数据类型和... 目录一、Redis 入门介绍二、Redis 的五大基本数据类型2.1 String 类型2.2 Hash

Redis中Hash从使用过程到原理说明

《Redis中Hash从使用过程到原理说明》RedisHash结构用于存储字段-值对,适合对象数据,支持HSET、HGET等命令,采用ziplist或hashtable编码,通过渐进式rehash优化... 目录一、开篇:Hash就像超市的货架二、Hash的基本使用1. 常用命令示例2. Java操作示例三

Linux创建服务使用systemctl管理详解

《Linux创建服务使用systemctl管理详解》文章指导在Linux中创建systemd服务,设置文件权限为所有者读写、其他只读,重新加载配置,启动服务并检查状态,确保服务正常运行,关键步骤包括权... 目录创建服务 /usr/lib/systemd/system/设置服务文件权限:所有者读写js,其他