当前位置:首页 > 技术 > 正文内容

Android中LAME实现PCM到MP3的音频转码

访客 技术 2026年5月26日 3

LAME编码器集成与配置

LAME作为开源MP3编码器,在高比特率和VBR编码场景表现优异。在Android中集成需通过NDK实现,主要流程如下:

环境准备

  1. 官网下载LAME源码(以3.100为例)
  2. 创建Android Studio C++项目
  3. 在cpp目录新建lamemp3文件夹,复制以下文件:
    • libmp3lame目录所有.c/.h文件
    • include/lame.h头文件

源码修改

  1. 移除fft.c中第47行:#include "vector/lame_intrin.h"
  2. 修改set_get.h第24行为:#include "lame.h"
  3. 替换util.h第574行为:extern float fast_log2(float x);

Gradle配置

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

CMake构建配置

cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lameLibs/${ANDROID_ABI})

file(GLOB LAME_SRC "lamemp3/*.c")
file(GLOB LAME_CPP "lamemp3/*.cpp")
include_directories(${CMAKE_CURRENT_LIST_DIR}/lamemp3)

add_library(audio_codec SHARED
  native-lib.cpp
  ${LAME_SRC}
  ${LAME_CPP}
)

find_library(log-lib log)
target_link_libraries(audio_codec ${log-lib})

音频转码核心实现

pcm2mp3.h头文件定义接口:

class PCMEncoder {
public:
  int init(const char* pcmPath, const char* mp3Path, 
           int sampleRate, int channels, int bitrate);
  void encode();
  ~PCMEncoder();
private:
  FILE* pcmFile;
  FILE* mp3File;
  lame_global_flags* encoder;
};

转码逻辑实现:

int PCMEncoder::init(const char* pcmPath, const char* mp3Path, 
                    int sampleRate, int channels, int bitrate) {
  pcmFile = fopen(pcmPath, "rb");
  mp3File = fopen(mp3Path, "wb");
  if(!pcmFile || !mp3File) return -1;

  encoder = lame_init();
  lame_set_in_samplerate(encoder, sampleRate);
  lame_set_num_channels(encoder, channels);
  lame_set_brate(encoder, bitrate);
  lame_set_quality(encoder, 2);
  lame_init_params(encoder);
  return 0;
}

void PCMEncoder::encode() {
  const int BUFFER_SIZE = 131072; // 128KB
  short* pcmBuffer = new short[BUFFER_SIZE];
  short* leftChannel = new short[BUFFER_SIZE/2];
  short* rightChannel = new short[BUFFER_SIZE/2];
  unsigned char* mp3Buffer = new unsigned char[BUFFER_SIZE];

  while(size_t read = fread(pcmBuffer, 2, BUFFER_SIZE, pcmFile)) {
    // 分离声道
    for(int i=0; i<read; i+=2) {
      leftChannel[i/2] = pcmBuffer[i];
      rightChannel[i/2] = pcmBuffer[i+1];
    }
    int encoded = lame_encode_buffer(encoder, leftChannel, rightChannel, 
                                    read/2, mp3Buffer, BUFFER_SIZE);
    fwrite(mp3Buffer, 1, encoded, mp3File);
  }

  // 释放资源
  delete[] pcmBuffer;
  delete[] leftChannel;
  delete[] rightChannel;
  delete[] mp3Buffer;
}

JNI接口封装

Java层调用接口:

public class AudioEncoder {
  static { System.loadLibrary("audio_codec"); }
  public native String getVersion();
  public native int encodePcmToMp3(String pcmPath, String mp3Path,
                                  int sampleRate, int channels, int bitrate);
  public native void release();
}

JNI实现层:

PCMEncoder* encoder;

JNIEXPORT jint JNICALL
Java_com_example_AudioEncoder_encodePcmToMp3(JNIEnv* env, jobject obj,
                                            jstring pcmPath, jstring mp3Path,
                                            jint sampleRate, jint channels, jint bitrate) {
  const char* inPath = env->GetStringUTFChars(pcmPath, nullptr);
  const char* outPath = env->GetStringUTFChars(mp3Path, nullptr);
  
  encoder = new PCMEncoder();
  int status = encoder->init(inPath, outPath, sampleRate, channels, bitrate);
  if(status == 0) {
    encoder->encode();
  }

  env->ReleaseStringUTFChars(pcmPath, inPath);
  env->ReleaseStringUTFChars(mp3Path, outPath);
  return status;
}

Java层调用示例

// 注意:根据实际设备调整采样率参数
audioEncoder.encodePcmToMp3(
  pcmFile.getAbsolutePath(),
  mp3File.getAbsolutePath(),
  sampleRate / 2, 
  (channelConfig == AudioFormat.CHANNEL_IN_MONO) ? 1 : 2,
  128
);

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。