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

接下来在原来的项目中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 JNICALLJava_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
以及《音视频开发进阶指南》

更多相关文章

  1. 代码文件android:向手机卡上写入文件时总是不成功,解决办法
  2. Android菜鸟日记25-android反编译
  3. Android(安卓)中级学习心得
  4. 在Eclipse下编译Android原生APK方法
  5. Android兼容库
  6. 各位大佬都是怎么开发调试系统应用的
  7. android 获取本地存储文件是否在某一段时间内更新过
  8. Android(安卓)WiFiDirect 一个jar包搞定一切
  9. Android中有用的Item选中和按下去的样式

随机推荐

  1. MySQL修炼之联结与集合浅析
  2. 如何利用MySQL的binlog恢复误删数据库详
  3. 深入理解Mysql事务隔离级别与锁机制问题
  4. MySql escape的使用案例详解
  5. MySql数据库单表查询与多表连接查询效率
  6. MySQL数据库分组查询group by语句详解
  7. MySQL时间类型和模式详情
  8. MySQL 中 datetime 和 timestamp 的区别
  9. 基于Mysql+JavaSwing的超市商品管理系统
  10. MySQL深分页问题解决的实战记录