前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android中使用LAME库生成MP3文件

Android中使用LAME库生成MP3文件

原创
作者头像
fdroid
发布2019-01-08 14:57:42
3.9K0
发布2019-01-08 14:57:42
举报
文章被收录于专栏:Android填坑指南

前言

Android中内置的MediaCodeC提供了很多音视频编解码器,但由于MP3是有版权的,所以原生MediaCodeC只提供了MP3的解码能力,对于MP3的编码就需要借助外部库了。LAME库由开源社区开发,当前是公认有损质量MP3中压缩效果最好的编码器。本文的主要工作为将LAME源码编译为so库,并在Android中使用。

LAME源码

  1. LAME源码下载:LAME目前最新版本为3.100,http://lame.sourceforge.net/
  2. 新建Android项目,并在创建时勾选Include C++ support,创建项目后,可以发现在app/src/main目录下有cpp和java两个目录。
  3. 将源码中lame-3.100/libmp3lame目录复制到app/src/main/cpp目录中,仅保留.h和.c文件,另外还需复制lame-3.100/includes/lame.h文件到项目cpp目录下。
  4. 修改部分文件 1) 删除fft.c文件的vector引用include "vector/lame_intrin.h" 2) 将set_get.h中的 #include <lame.h> 修改为 #include "lame.h" 3) 将util.h文件的574行的extern ieee754_float32_t fast_log2(ieee754_float32_t x); 替换为 extern float fast_log2(float x);

LAME编译

1. C++项目的编译有两种方式: 1) CMake:Android Studio新的构建方式,在build.gradle中指定CMakeList.txt文件路径,jni会按照这个脚本来进行编译。 2) ndk-build:老eclipse的构建方式,也就是Android.mk的形式。

2. 本文介绍第一种方式 修改app目录下的CMakeList.txt,由于lame源码需要编译的文件较多,可以使用以下方式编译整个文件夹

代码语言:javascript
复制
aux_source_directory(src/main/cpp/libmp3lame LAME_SRC_DIR)
add_library(lame-lib SHARED lame-lib.cpp ${LAME_SRC_DIR})

3. 在app/build.gradle中配置cmake参数

代码语言:javascript
复制
externalNativeBuild {
    cmake {
        cFlags "-DSTDC_HEADERS"  // 必须,给编译器加上STDC头文件的宏定义
        abiFilters "armeabi-v7a" // 可选,指定生成so的兼容的架构
   }
}

4. 编辑lame-lib.cpp文件,调用lame方法

代码语言:javascript
复制
extern "C" {
JNIEXPORT jstring JNICALL
Java_com_demo_lame_MainActivity_stringFromJNI2(
        JNIEnv *env,
        jobject /* this */) {
    return env->NewStringUTF(get_lame_version());
}
}

5. 编译项目,可在屏幕上看到lame的版本号

使用LAME生成MP3

在lame-lib.cpp中添加以下代码,lame初始化时采样率等参数的要求可在lame源码中看到。最后在MainActivity中调用wav2mp3方法即可。

代码语言:javascript
复制
int BUFF_SIZE = 8192;

JNIEXPORT void JNICALL Java_com_demo_lame_MainActivity_wav2mp3
        (JNIEnv *env, jobject obj, jstring jwav, jstring jmp3, jint inSampleRate, jint inChannels, jint outSampleRate, jint byteRate, jint mode, jint quality) {

    jboolean isCopy;
    const char *cwav = env->GetStringUTFChars(jwav, &isCopy);
    const char *cmp3 = env->GetStringUTFChars(jmp3, &isCopy);

    // 打开wav文件
    FILE *fwav = fopen(cwav, "rb");
    
    // 移除wav文件头
    fseek(fwav, 4 * 1024, SEEK_CUR);
    
    FILE *fmp3 = fopen(cmp3, "wb+");

    int channel = inChannels;

    short int wav_buffer[BUFF_SIZE * channel];
    unsigned char mp3_buffer[BUFF_SIZE];

    // init lame
    lame_global_flags *lameConvert;
    lameConvert = lame_init();

    lame_set_in_samplerate(lameConvert, inSampleRate);
    lame_set_num_channels(lameConvert, inChannels);
    lame_set_out_samplerate(lameConvert, outSampleRate);
    if (byteRate > 0) {
        lame_set_brate(lameConvert, byteRate);
    }
    lame_set_mode(lameConvert, (MPEG_mode) mode);
    lame_set_quality(lameConvert, quality);

    lame_set_VBR(lameConvert, vbr_default);
    lame_init_params(lameConvert);
    int read;
    int write;
    int total = 0;
    do {
        read = fread(wav_buffer, sizeof(short int) * channel, BUFF_SIZE, fwav);
        total += read * sizeof(short int) * channel;
        if (read != 0) {
            write = lame_encode_buffer(lameConvert, wav_buffer, nullptr, read, mp3_buffer, BUFF_SIZE);
        } else {
            write = lame_encode_flush(lameConvert, mp3_buffer, BUFF_SIZE);
        }
        fwrite(mp3_buffer, 1, write, fmp3);

    } while (read != 0);
    lame_mp3_tags_fid(lameConvert, fmp3);
    lame_close(lameConvert);
    fclose(fwav);
    fclose(fmp3);
}

参考

  1. https://www.jianshu.com/p/612e96910003
  2. https://www.jianshu.com/p/6332418b12b1

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • LAME源码
  • LAME编译
  • 使用LAME生成MP3
  • 参考
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档