您的位置:首页 > 移动开发 > Android开发

Android 之NDK实战系列(3)——Android Studio下使用lame 进行简单的转换

2016-12-05 14:57 393 查看
首先,介绍下今天使用的工具——Lame

LAME 是最好的MP3编码器,编码高品质MP3的最好也是唯一的选择。LAME本身是控制台程序,需要加外壳程序才比较容易使用,也可以在别的软件(比如EAC)中间调用。是一款出色的MP3压缩程序,它使用了独创的人体听音心理学模型和声学模型,改变了人们对MP3高音发哑、低音发破的音质的印象。——百度百科

通过前两篇博文,大家已经对C、NDK的使用有了一定的认识,现在就逐渐深入NDK的使用

录音功能在我们日常生活中使用十分频繁,通过此功能,我们免去了大量用于打字的时间,在APP中植入语音模块也变得尤为重要,但是,通常情况下,本地录音保存的音频文件都是wav类型(无损原音),但是,如果该文件用于本地保存,或者网络传输,相比较主流的mp3文件,在音质相近的情况下,我们需要消耗更多的本地内存和网络流量。所以,为了优化app,我们需要对音频格式进行转化。而Lame就提供了这一功能。

首先,我们登陆Lame 进行开发包的下载,在下载的压缩包中,有大量的c,cpp文件,这些都是用于实现音频转化的工具

现在,我们创建一个项目,暂且命名为DemoLame

先预览下项目的目录结构



因为我们在Demo中只实现wav mp3的转换,所以项目中就一个Activity 和一个Lame工具类

因为应用涉及文件的读取,我们在Manifest 中加入响应的权限

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>


在gradle 中进行配置,这里就不多解释了,如果不懂就翻阅前两篇博文

ndk {
moduleName "converMp3" //设置.so文件名称
ldLibs "log"
abiFilters "armeabi", "armeabi-v7a", "x86"
}


编写LameUtils

public class LameUtils {
static {
System.loadLibrary("converMp3");
}
public static native void conver(String sourWav,String sourMp3);
}


静态代码块调用so链接库,native调用本地方法,还是那句话,不懂就翻前两篇博文

敲黑板!!重点来了

C/C++文件的添加

打开我们下载的开发包,打开libmp3lame文件夹,把文件夹下所有的文件添加到jni文件夹下,(其实重要复制C/C++文件就够了,有很多是图标文件,但是如果你懒,留在项目里影响也不大),接着回到根目录,把include文件夹下的lame.h也复制到jni文件夹下,现在,我们已经将所需要的文件添加到我们的项目中了。

我们来对一些C代码进行修改

1、因为我们刚才更改了lame.h的路径,所以把set_get.h中的#include改成#include "lame.h"

2、把utils.h中 extern ieee754_float32_t fast_log2(ieee754_float32_t x) 的ieee754_float32_t
改成浮点型float,这是Linux下的编写习惯

3、删除fft.c 中的#include
"vector/lame_intrin.h",这是对CPU的优化,手持端暂时用不到

修改C代码后,我们编译下LameUtils,实现jni方法

#include "com_adrian_demolame_LameUtils.h"
#include "lame.h"
#include <android/log.h>
#include <string.h>

#define TAG "lamedemo" // LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // LOGF类型

JNIEXPORT void JNICALL Java_com_adrian_demolame_LameUtils_conver
(JNIEnv * env, jclass obj, jstring wavresoucre, jstring mp3resource){
//获取路径
char *cwav = (*env)->GetStringUTFChars(env, wavresoucre, 0);
char *cmp3 = (*env)->GetStringUTFChars(env, mp3resource, 0);
LOGE("源文件路径是%s", cwav);
LOGE("转化件路径是%s", cmp3);

//定义缓冲
short int wav_buffer[8192 * 2];
unsigned char mp3_buffer[8192];

//加载文件
FILE *fwav = fopen(cwav, "rb");//rb 二进制 读取
FILE *fmp3 = fopen(cmp3, "wb");

//初始化lame编码器
lame_t lame = lame_init();
//2. 设置lame mp3编码的采样率
lame_set_in_samplerate(lame, 44100);
lame_set_num_channels(lame, 2);
// 3. 设置MP3的编码方式
lame_set_VBR(lame, vbr_default);

lame_init_params(lame);

LOGE("Lame初始化完成");

int read;
int write;
int total = 0; // 当前读的wav文件的byte数目
//循环读取转化
do
{
read = fread(wav_buffer, sizeof(short int) * 2, 8192, fwav);
total += read * sizeof(short int) * 2;//read是实际读取的次数
LOGE("converting ....%d", total);
// 调用java代码 完成进度条的更新
if (read != 0)
{

write = lame_encode_buffer_interleaved(lame, wav_buffer, read, mp3_buffer, 8192);
//把转化后的mp3数据写到文件里
fwrite(mp3_buffer, sizeof(unsigned char), write, fmp3);
}
if (read == 0)
{
lame_encode_flush(lame, mp3_buffer, 8192);
}
} while (read != 0);

LOGE("convert  finish");
lame_close(lame);
fclose(fwav);//关闭文件操作句柄
fclose(fmp3);
}


注解都在代码里面了

最后,在Activity中添加LameUtils的调用

public class MainActivity extends AppCompatActivity {

private Button mBtnConver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBtnConver = (Button)findViewById(R.id.btn_conver);
mBtnConver.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
final File path = Environment.getExternalStorageDirectory();
File file = new File(path.getAbsolutePath() + "/test.wav");
new Thread() {
@Override
public void run() {
LameUtils.conver(path.getAbsolutePath()+"/test.wav",path.getAbsolutePath()+"/conver.mp3");
}
}.start();

}
});
}
}


由于这是一个耗时事件,我把转换过程放入到一个线程中,转换后在同级目录下会有一个conver.mp3文件,对了,我事先在根目录下存放了一个名为test.wav的音频文件,如果没有地址的传入容易报空指针。

Demo下载
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ndk c语言 Android Lame