Android通过lame进行音频格式转换

之前项目中遇到过手机录音问题,Android端录制的格式为amr,但是却没法在iOS端播放,于是找到了通过lame库进行格式转换的方法,我们通过AudioRecord录制出原生的pcm格式音频,然后通过lame库进行格式转换,这里需要用到NDK,所以我们需要配置NDK开发环境。主要就是以下,具体不细说了。
Android通过lame进行音频格式转换_第1张图片
接下来在原来的项目中build.gradle中添加如下代码

android {
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
        }
    }
}

然后在main文件夹下创建cpp/CMakeLists.txt文件

# Sets the minimum version of CMake required to build the native library.
# 这里的3.4.1是我这里的cmake版本  这个可以直接创建一个ndk项目进行查看
cmake_minimum_required(VERSION 3.4.1)

add_library( # Sets the name of the library.
        lame

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).

        lame.cpp
        )

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( # Specifies the target library.
        lame

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

然后在cpp文件夹下创建一个lame.cpp ,添加如下代码测试

#include <jni.h>
#include <string>

extern "C"
JNIEXPORT jstring JNICALL
Java_com_we_convertdemo_Convert_stringFromJNI(JNIEnv *env, jobject) {

    std::string hello = "Hello from C++";

    return env->NewStringUTF(hello.c_str());
}

接着在我们的Java项目中创建一个Convert类添加如下代码:

public class Convert {
    static {
        System.loadLibrary("lame");
    }
    public native String stringFromJNI();
}

然后在activity当中调用测试一下通过即可。
lame包下载地址https://sourceforge.net/projects/lame/files/lame/
接下来解压该文件后找到libmp3lame文件夹,将该文件夹下面的.c和.h文件复制到项目的cpp文件夹下(该文件夹里面的文件夹不用管),接着把include目录下的lame.h文件也放到cpp目录当中。然后把所有的.c文件添加到CMakeList.txt文件的add_library中。同时对当中的部分文件做修改
1.在 fft.c 文件中删除 #include “vector/lame_intrin.h”
2.在set_get.h 文件中修改 #include 为 #include“lame.h”
3.在 util.h 文件中将”extern ieee754_float32_t fast_log2(ieee754_float32_t x);”修改为 “extern float fast_log2(float x);”
修改完上诉文件后,我们编译一下会报错,接下来需要添加如下配置

cmake {         
           cFlags "-DSTDC_HEADERS"
          cppFlags "-fexceptions", "-frtti"
     }

接下来我们在Convert类中添加如下三个方法:

 public native int init(String pcmPath,int audioChannels,int bitRate,int sampleRate,String mp3Path);
    public native void encode();
    public native void destroy();

然后实现创建两个编码类Mp3Encoder.h和Mp3Encoder.cpp
代码如下


#include <cstdio>
#include "lame.h"

class Mp3Encoder {
private:
    FILE* pcmFile;
    FILE* mp3File;
    lame_t lameClient;
public:
    Mp3Encoder();
    ~Mp3Encoder();
    int Init(const char* pcmFilePath,int channels,int bitRate,int sampleRate,const char* mp3FilePath);
    void Encode();
    void Destory();
};
---------------------------------------------------------------------------------------

#include "Mp3Encoder.h"

Mp3Encoder::Mp3Encoder() {}

Mp3Encoder::~Mp3Encoder() {}

int Mp3Encoder::Init(const char *pcmFilePath, int channels, int bitRate, int sampleRate,
                     const char *mp3FilePath) {
    int ret  = -1;
    pcmFile = fopen(pcmFilePath,"rb");
    if (pcmFile){
        mp3File = fopen(mp3FilePath,"wb");
        if (mp3File){
            lameClient = lame_init();
            lame_set_in_samplerate(lameClient,sampleRate);
            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,leftBuffer,rightBuffer
                ,readBufferSize/2,mp3_buffer,buffersize);
        fwrite(mp3_buffer,1,wroteSize,mp3File);
    }

    delete[] buffer;
    delete[] leftBuffer;
    delete[] rightBuffer;
    delete[] mp3_buffer;
}

void Mp3Encoder::Destory() {
    if(pcmFile){
        fclose(pcmFile);
    }
    if (mp3File){
        fclose(mp3File);
        lame_close(lameClient);
    }
}

然后把我们把所有的.c文件和.cpp文件添加到CMakeLists.txt的add_library中

add_library( # Sets the name of the library.
        lame

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).

        lame.cpp

        Mp3Encoder.cpp

        bitstream.c
        encoder.c
        fft.c
        gain_analysis.c
        id3tag.c
        lame.c
        mpglib_interface.c
        newmdct.c
        presets.c
        psymodel.c
        quantize.c
        quantize_pvt.c
        reservoir.c
        set_get.c
        tables.c
        takehiro.c
        util.c
        vbrquantize.c
        VbrTag.c
        version.c
        )

具体代码已经上传到github上可以下载查看
https://github.com/honghengqiang/ConvertDemo.git

参考文档:
https://developer.android.com/studio/projects/gradle-external-native-builds
https://developer.android.com/ndk/guides/cpp-support
以及《音视频开发进阶指南》

你可能感兴趣的:(Android)