一、LAME简介

LAME是目前非常优秀的一种MP3编码引擎,在业界,转码成Mp3格式的音频文件时,最常用的就是LAME库。当达到320Kbit/s时,LAME编码出来的音频质量几乎可以和CD的音质相媲美,并且还能保证整个音频文件的体积非常小,因此若要在移动端平台上编码MP3文件,使用LAME便成为唯一的选择。

二、使用场景

操作系统:Android。

场景:

1.录音时保存Mp3格式的文件

2. 将wav无损音频文件转码成mp3这种体积相对较小的音频文件。

3.可以将获取到的音频流进行录制保存为mp3格式。

三、开发准备

LAME的源码是托管到sourceforge.net上的,我们开发一个基于LAME的项目,就不得不下载其源码用于编译。

如果需要集成到Android系统上,就需要开发者具备一些NDK开发的能力。

四、开发过程

下面针对Android使用Lame做了基本的封装,供实际开发过程中进行参考:

首先,在java类中定义native方法。

private static native long nInit(int inSampleRate, int inChannels, int outSampleRate, int outBitrate, int model, intquality);private static native int nGetVersion(longlamePtr);private static native int mGetMp3bufferSize(longlamePtr);private static native int mGetMp3bufferSizeWithSamples(long lamePtr, intsamples);private static native int nEncodeShortInterleaved(long lamePtr, short[] bufLR, int samples, byte[] outMp3buf);private static native int nEncodeShort(long lamePtr, short[] bufL, short[] bufR, int samples, byte[] outMp3buf);private static native int nFlush(long lamePtr, byte[] outBuf);private static native void nClose(long lamePtr);

生成相应的.h的头文件,并实现该头文件,完成整体逻辑的编写。

#include #include#include#include"com_renhui_lame_Lame.h"#include"libmp3lame/lame.h"

extern "C"JNIEXPORT jlong JNICALL Java_com_renhui_lame_Lame_nInit(JNIEnv*env, jclass type, jint inSampleRate, jint inChannels,

jint outSampleRate, jint outBitrate, jint model, jint quality) {

lame_global_flags*lameFlags;

lameFlags=lame_init();

lame_set_in_samplerate(lameFlags, inSampleRate);

lame_set_num_channels(lameFlags, inChannels);

lame_set_out_samplerate(lameFlags, outSampleRate);

lame_set_brate(lameFlags, outBitrate);

lame_set_mode(lameFlags, (MPEG_mode) model);

lame_set_quality(lameFlags, quality);int code =lame_init_params(lameFlags);if (code != 0) {

lame_close(lameFlags);returncode;

}return (long) lameFlags;

}

JNIEXPORT jint JNICALL Java_com_renhui_lame_Lame_nGetVersion(JNIEnv*env, jclass type, jlong lamePtr) {

lame_global_flags*lameFlags;

lameFlags= (lame_global_flags *) lamePtr;returnlame_get_version(lameFlags);

}

JNIEXPORT jint JNICALL Java_com_renhui_lame_Lame_mGetMp3bufferSize(JNIEnv*env, jclass type, jlong lamePtr) {

lame_global_flags*lameFlags;

lameFlags= (lame_global_flags *) lamePtr;returnlame_get_size_mp3buffer(lameFlags);

}

JNIEXPORT jint JNICALL Java_com_renhui_lame_Lame_mGetMp3bufferSizeWithSamples(JNIEnv*env, jclass type, jlong lamePtr, jint samples) {

lame_global_flags*lameFlags;

lameFlags= (lame_global_flags *) lamePtr;int version =lame_get_version(lameFlags);int bitrate =lame_get_brate(lameFlags);int sampleRate =lame_get_out_samplerate(lameFlags);float p = (bitrate / 8.0f) /sampleRate;if (version == 0) {//MPEG2: num_samples*(bitrate/8)/samplerate + 4*576*(bitrate/8)/samplerate + 256

return (jint) ceil(samples * p + 4 * 576 * p + 256);

}else if (version == 1) {//MPEG1: num_samples*(bitrate/8)/samplerate + 4*1152*(bitrate/8)/samplerate + 512

return (jint) ceil(samples * p + 4 * 1152 * p + 512);

}else{return (jint) ceil((1.25 * samples + 7200));

}

}

JNIEXPORT jint JNICALL Java_com_renhui_lame_Lame_nEncodeShortInterleaved(JNIEnv*env, jclass type, jlong lamePtr,

jshortArray bufLR_, jint samples, jbyteArray outMp3buf_) {

lame_global_flags*lameFlags;

lameFlags= (lame_global_flags *) lamePtr;

jshort*bufLR = env->GetShortArrayElements(bufLR_, NULL);

jbyte*outMp3buf = env->GetByteArrayElements(outMp3buf_, NULL);const jsize outMp3bufSize = env->GetArrayLength(outMp3buf_);int result =lame_encode_buffer_interleaved(lameFlags, bufLR, samples,

(u_char*) outMp3buf, outMp3bufSize);

env->ReleaseShortArrayElements(bufLR_, bufLR, 0);

env->ReleaseByteArrayElements(outMp3buf_, outMp3buf, 0);returnresult;

}

JNIEXPORT jint JNICALL

Java_com_renhui_lame_Lame_nEncodeShort(JNIEnv*env, jclass type, jlong lamePtr, jshortArray bufL_,

jshortArray bufR_, jint samples, jbyteArray outMp3buf_) {

lame_global_flags*lameFlags;

lameFlags= (lame_global_flags *) lamePtr;

jshort*bufL = env->GetShortArrayElements(bufL_, NULL);

jshort*bufR = env->GetShortArrayElements(bufR_, NULL);

jbyte*outMp3buf = env->GetByteArrayElements(outMp3buf_, NULL);const jsize outMp3bufSize = env->GetArrayLength(outMp3buf_);int result =lame_encode_buffer(lameFlags, bufL, bufR, samples,

(u_char*) outMp3buf, outMp3bufSize);

env->ReleaseShortArrayElements(bufL_, bufL, 0);

env->ReleaseShortArrayElements(bufR_, bufR, 0);

env->ReleaseByteArrayElements(outMp3buf_, outMp3buf, 0);returnresult;

}

JNIEXPORT jint JNICALL

Java_com_renhui_lame_Lame_nFlush(JNIEnv*env, jclass type, jlong lamePtr, jbyteArray outBuf_) {

lame_global_flags*lameFlags;

lameFlags= (lame_global_flags *) lamePtr;

jbyte*outBuf = env->GetByteArrayElements(outBuf_, NULL);const jsize outBufSize = env->GetArrayLength(outBuf_);int result = lame_encode_flush(lameFlags, (u_char *) outBuf, outBufSize);

env->ReleaseByteArrayElements(outBuf_, outBuf, 0);returnresult;

}

JNIEXPORTvoidJNICALL

Java_com_renhui_lame_Lame_nClose(JNIEnv*env, jclass type, jlong lamePtr) {

lame_global_flags*lameFlags;

lameFlags= (lame_global_flags *) lamePtr;

lame_close(lameFlags);

}

编写Android.mk和Application.mk,为ndk-build打包做准备。

Android.mk:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE :=mp3lame

LAME_LIBMP3_DIR :=libmp3lame

LOCAL_SRC_FILES :=\

$(LAME_LIBMP3_DIR)/bitstream.c \

$(LAME_LIBMP3_DIR)/fft.c \

$(LAME_LIBMP3_DIR)/id3tag.c \

$(LAME_LIBMP3_DIR)/mpglib_interface.c \

$(LAME_LIBMP3_DIR)/presets.c \

$(LAME_LIBMP3_DIR)/quantize.c \

$(LAME_LIBMP3_DIR)/reservoir.c \

$(LAME_LIBMP3_DIR)/tables.c \

$(LAME_LIBMP3_DIR)/util.c \

$(LAME_LIBMP3_DIR)/VbrTag.c \

$(LAME_LIBMP3_DIR)/encoder.c \

$(LAME_LIBMP3_DIR)/gain_analysis.c \

$(LAME_LIBMP3_DIR)/lame.c \

$(LAME_LIBMP3_DIR)/newmdct.c \

$(LAME_LIBMP3_DIR)/psymodel.c \

$(LAME_LIBMP3_DIR)/quantize_pvt.c \

$(LAME_LIBMP3_DIR)/set_get.c \

$(LAME_LIBMP3_DIR)/takehiro.c \

$(LAME_LIBMP3_DIR)/vbrquantize.c \

$(LAME_LIBMP3_DIR)/version.c \

com_renhui_lame_Lame.cpp

LOCAL_C_INCLUDES += $(LOCAL_PATH)/mp3lame

LOCAL_LDLIBS := -llog -lz

include $(BUILD_SHARED_LIBRARY)

Application.mk:

APP_ABI := all

#APP_ABI := armeabi armeabi-v7a x86

# APP_ABI :=armeabi

APP_PLATFORM := android-14

五、Lame重点API说明

1. lame_init()

lame_init() 用于初始化lame引擎,初始化完成后可以设置输入的相关参数:比特率、通道数。

注意:这些参数需要了解清楚需求后进行设置,否则转码出来的音频可能出现时长或者播放的问题。

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);

2. lame_encode_buffer()和 lame_encode_buffer_interleaved()

if (channels == 2) {

write= lame_encode_buffer_interleaved(gfp, input_buffer, read, mp3_buffer,MP3BUFSIZE);//立体声用此方法编码

} else if (channels == 1) {

write= lame_encode_buffer(gfp, input_buffer, input_buffer, read,mp3_buffer, MP3BUFSIZE);//单声道

}

3. lame_mp3_tags_fid(gfp,outfp)

在lame_encode_flush(gfp,mp3_buffer, sizeof(mp3_buffer))方法之后,lame_close(gfp)之前调用lame_mp3_tags_fid(gfp,outfp)方法为MP3文件添加vbr头,播放器才能正读取时间。

六、思维拓展

实战:

1. 录音为Mp3格式:(代码已转private)

2. 将wav格式的音频文件转码为Mp3格式:(代码已转private)

推荐资料:

java lame_音视频编解码——LAME相关推荐

  1. 各种音视频编解码学习详解之 编解码学习笔记(四):Mpeg系列——Mpeg 4

    最近在研究音视频编解码这一块儿,看到@bitbit大神写的[各种音视频编解码学习详解]这篇文章,非常感谢,佩服的五体投地.奈何大神这边文章太长,在这里我把它分解成很多小的篇幅,方便阅读.大神博客传送门 ...

  2. 音视频编解码学习详解

    音视频编解码学习详解 目录(?)[+] 编解码学习笔记二codec类型 编解码学习笔记三Mpeg系列Mpeg 1和Mpeg 2 编解码学习笔记四Mpeg系列Mpeg 4 编解码学习笔记五Mpeg系列A ...

  3. 音视频编解码知识学习详解(分多部分进行详细分析)

    1. 常用的基本知识 基本概念 编解码 编解码器(codec)指的是一个能够对一个信号或者一个数据流进行变换的设备或者程序.这里指的变换既包括将信号或者数据流进行编码(通常是为了传输.存储或者加密)或 ...

  4. 音视频编解码类开源项目的18个实时

    实时音视频的开发学习有很多可以参考的开源项目. 一个实时音视频应用共包括几个环节:采集.编码.前后处理.传输.解码.缓冲.渲染等很多环节.每一个细分环节,还有更细分的技术模块.比如,前后处理环节有美颜 ...

  5. 各种音视频编解码学习详解之 编解码学习笔记(十):Ogg系列

    最近在研究音视频编解码这一块儿,看到@bitbit大神写的[各种音视频编解码学习详解]这篇文章,非常感谢,佩服的五体投地.奈何大神这边文章太长,在这里我把它分解成很多小的篇幅,方便阅读.大神博客传送门 ...

  6. 音视频编解码的国际标准

    文章目录 1 音视频编解码的国际标准 1.1 音视频编解码相关的组织 1.2 H.265介绍 1 音视频编解码的国际标准 1.1 音视频编解码相关的组织 音视频编解码主要有如下三大组织推动并发展: I ...

  7. WebRTC 中收集音视频编解码能力

    在 WebRTC 中,交互的两端在建立连接过程中,需要通过 ICE 协议,交换各自的音视频编解码能力,如编解码器和编解码器的一些参数配置,并协商出一组配置和参数,用于后续的音视频传输过程. 对于音频, ...

  8. linux视音频解码教程,音视频编解码:NVIDIA Jetson Linux Multimedia API(总结)

    音视频编解码:NVIDIA Jetson Linux Multimedia API(总结) 2020年12月02日 | 萬仟网IT编程 | 我要评论 一.官网链接官网链接:https://docs.n ...

  9. mplayer 所支持的音视频编解码

    这里我把mplayer 所支持的音视频编解码都罗列出来,方便大家查阅: ---------------------------------------------------------------- ...

  10. 音视频编解码的一些源代码

    音视频编解码的一些源代码 (转) 资料名称:音视频编解码的一些源代码 资料成文时间:不详 语言:英文 页数:很多 何人所著(来源): 文件格式:原代码 开发工具:vc++ 说明: 以下上传的源码是我以 ...

最新文章

  1. python 手动读取cifar10_Python读入CIFAR-10数据库
  2. C# winform WebBrowser怎么获取js中的变量的值?怎么触发js的事件?
  3. 如何在 Windows 主机上访问本地局域网中的 Linux 主机
  4. C语言的代码内存布局
  5. Vue.js学习笔记(一) - 起步
  6. 一年Android工作经验,一举拿下百度、网易、美团、小米、快手等Offer面经
  7. Golang 入门系列(十三)用Beego开发web应用
  8. 理解OAuth2授权框架
  9. 换热站实际应用程序:西门子200smart PLC与威纶通触摸屏换热站程序、西门子1200plc与昆仑通态触摸屏换热站程序
  10. bootmgr快速修复win7_这可能是史上最简单的一键安装虚拟机win7系统了
  11. java 设置时区_Java Calendar如何设置时区
  12. 详解区块链中EOS的作用。
  13. 一个简单的敌人自动寻找玩家进行攻击及受到伤害死亡效果实现
  14. GNSS 使用DFT算法 能量损耗仿真
  15. 什么是策划?策划的真正含义是什么?
  16. C语言学习周报(第四周)
  17. 关于shader的内存占用分析,以urp项目内置shader Lit为例
  18. PHP代码审计8—SSRF 漏洞
  19. linux批量修改文件时间
  20. 【java】javamail简介以及发送邮件

热门文章

  1. Mysql数据库优化
  2. 移动硬盘遇到无法访问,文件或目录损坏且无法读取的解决办法
  3. 网络爬虫(基于python的网络爬虫批量爬取图片)
  4. matlab一维数组操作,Matlab创建一维数组的具体操作方法
  5. Go语言 defer 和 recover
  6. 盖世兔I9100刷机心得
  7. 《腾讯传》四、从寄生虫到蜕变上市—企鹅的成人礼
  8. python图片鉴黄_深夜,使用NSFW尝试一下图片鉴黄
  9. 计算机图形表示的原理
  10. 不灭鸿蒙等级划分,等级划分