Android通过lame进行音频格式转换
之前项目中遇到过手机录音问题,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
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:向手机卡上写入文件时总是不成功,解决办法
- Android菜鸟日记25-android反编译
- Android(安卓)中级学习心得
- 在Eclipse下编译Android原生APK方法
- Android兼容库
- 各位大佬都是怎么开发调试系统应用的
- android 获取本地存储文件是否在某一段时间内更新过
- Android(安卓)WiFiDirect 一个jar包搞定一切
- Android中有用的Item选中和按下去的样式