之前项目中遇到过手机录音问题,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 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
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
以及《音视频开发进阶指南》