音频转码(压缩)
来源:互联网 发布:centos配置网络 编辑:程序博客网 时间:2024/05/21 06:41
WAV转码Mp3
这里为大家讲述,48K采样率,128比特率的WAV音频转MP3,当然也是支持其他采样率音频转码的,需要你自己修改下本地方法,内置了完整的Lame转码库,懂C的完全可以做出一个全能的音频格式转换器,这里只举例一种情况,第一是为了给大家提供一条思路,第二也是为了抛砖引玉!!!(注释方面有偏差的请高手指正)老规矩,先贴图,这里贴两幅图。
第一幅,音频转码图:
第二幅:验证结果图--时间以及内容
(时间看得到,内容只能你们自己下源码,转码后再听了,百分百正确),注意,这里用到的wav是assets资源里面的,48K采样率,其他采样率音频转码时间可能有差别,内容上没差别,如果要精益求精,需要你们自己改jni中的源码,将采样率和采样率抽离出来动态赋值,看效果吧:
图贴了,我们接下来就讲技术和思路了,首先大家熟知的可以用来解码的本地库有FFmpeg,但是这个玩意太大,对于一般的音频处理这块我们这里选择用Lame库,相信用过linux的同学应该对这个非常熟悉,音频解码、转码好帮手,库可以自己去网上下载,当然我上传的源码里也是有的,应该是最新版,8月份下的,这里我们贴下转码的关键代码:
JNIEXPORT void JNICALL Java_com_example_lameonandroid_activity_SongList_convert(JNIEnv * env, jobject obj, jstring jwav, jstring jmp3){ //init lame lame_global_flags* gfp = lame_init(); lame_set_num_channels(gfp, 2);//设置声道数 lame_set_in_samplerate(gfp, 48000);//设置采样率(这里很重要,必须跟音频源一致,如果低于音频源,时间会变短,反之亦然) lame_set_brate(gfp, 128);//设置比特率 lame_set_mode(gfp,0);//* mode = 0,1,2,3 = stereo,jstereo,dualchannel(not supported),mono defaul lame_set_quality(gfp,2); /* 2=high 5 = medium 7=low */ // 3. 设置MP3的编码方式 lame_set_VBR(gfp, vbr_max_indicator); LOGE("init lame finished ..."); int initStatusCode = lame_init_params(gfp); if(initStatusCode >= 0){ //将Java的字符串转成C的字符串 char* cwav = Jstring2CStr(env, jwav); char* cmp3 = Jstring2CStr(env, jmp3); FILE* fwav = fopen(cwav, "rt"); FILE* fmp3 = fopen(cmp3, "wb"); //获取文件总长度 int length = get_file_size(cwav); LOGE("length = %d\n ",length); //每次读取的数据长度 const int WAV_SIZE = 8192*2;//在模拟信号中每秒取8192*4信号点 const int MP3_SIZE = 8192*2; short int wav_buffer[WAV_SIZE*2];//这里乘以2是因为取双声道,音频数据都是左声道一帧、右声道一帧循环方式的 unsigned char mp3_buffer[MP3_SIZE]; int read, write, total = 0; do{ //从fwav中读取数据缓存到wav_buffer,每次读取sizeof(short int)*2,读8192次, // 取出数据长度sizeof(short int)*2*WAV_SIZE read = fread(wav_buffer,sizeof(short int)*2,WAV_SIZE,fwav); if(read != 0){ total += read* sizeof(short int)*2; publishJavaProgress(env, obj, total); //第三个参数表示:每个通道取的数据长度 write = lame_encode_buffer_interleaved(gfp,wav_buffer,WAV_SIZE,mp3_buffer,MP3_SIZE); LOGE("write=%d\n ",write); }else{ //读到末尾 write = lame_encode_flush(gfp,mp3_buffer,MP3_SIZE); } //将转换后的数据缓存mp3_buffer写到fmp3文件里 fwrite(mp3_buffer,sizeof(unsigned char),write,fmp3); }while(read != 0); lame_close(gfp); fclose(fwav); fclose(fmp3); LOGE("convert completed..."); }}<pre name="code" class="java">//获取文件长度int get_file_size(char* filename){ struct stat statbuf; stat(filename,&statbuf); int size=statbuf.st_size; return size;}实际代码不多,当然这里有一个地方需要注意的是,从Java传过来的文件路径到了C这里需要稍微加点东西,不然会出错,加什么,加个“\0”,这是Java字符串和C字符串的差别,方法如下:
char* Jstring2CStr(JNIEnv* env, jstring jstr) { char* rtn = NULL; jclass clsstring = (*env)->FindClass(env, "java/lang/String"); jstring strencode = (*env)->NewStringUTF(env, "GB2312"); jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B"); jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid,strencode); // String .getByte("GB2312"); jsize alen = (*env)->GetArrayLength(env, barr); jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE); if (alen > 0) { rtn = (char*) malloc(alen + 1); //"\0" memcpy(rtn, ba, alen); rtn[alen] = 0; } (*env)->ReleaseByteArrayElements(env, barr, ba, 0); return rtn;}转码搞定了,但是我们怎么将转码的进度提示的数据传给Java用于进度条更新呢?这里就涉及到了C2Java,也是jni比较重要的部分,C2Java本质来讲是通过反射机制完成的,通过访问虚拟机生成的字节码文件达到访问Java类的目的,这里我贴下代码:
jclass clazz = 0;jmethodID methodid = 0;void publishJavaProgress(JNIEnv * env, jobject obj, jint progress) { // 调用java代码 更新程序的进度条 // 1.找到java的LameActivity的class if(clazz == 0){ //注意这里初始化clazz会分配一块内存,不能重复初始化,否则易导致内存溢出,这里的路径必须是全路径 clazz = (*env)->FindClass(env, "com/example/lameonandroid/activity/SongList"); } if (clazz == 0) { LOGI("can't find clazz"); } LOGI(" find clazz"); //2 找到class 里面的方法定义 // jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*); if(methodid == 0){ methodid = (*env)->GetMethodID(env, clazz, "updateProgress", "(I)V"); } if (methodid == 0) { LOGI("can't find methodid"); } LOGI(" find methodid"); // 这里就是调用Java中的<span style="line-height: 24px; font-family: Consolas;">updateProgress(int progress)方法</span> (*env)->CallVoidMethod(env, obj, methodid, progress);}给大家看下对应访问的Java中的方法:
Java代码就不贴了,就是简单的本地方法声明,以及编译头文件,当然为了照顾没有jni基础的同学,我会在下一章介绍下如何声明本地方法,并编译头文件。——jni-编译本地方法
最后还是要给到大家源码:LameForAndroid源码 1 0
- 音频转码(压缩)
- AAC音频压缩(转载)
- Unity 工具-Opus音频压缩(安卓篇)
- [转]音频动态压缩第三层(MPEG Audio Layer-3 即 mp3)
- 音频压缩编码 FAQ
- 音频压缩编码
- 音频压缩的原理
- 音频编码压缩技术
- 音频压缩格式
- ADPCM 音频压缩算法
- OGG音频压缩格式
- 音频压缩秘诀
- 音频压缩秘诀
- test_06:MPEG 音频压缩
- ADPCM音频压缩
- 音频压缩和编解码(Audio Compression and Codec)
- lame音频压缩解码(一)Lame知识小解
- lame音频压缩解码(二)之编译事例Demo
- 模板引擎freemarker的简单使用教程
- ubuntu开机找不到normal
- python入门:argparse浅析
- (iOS开发) 自定义悬浮按钮
- 单片机==lcd_笑脸(24)
- 音频转码(压缩)
- idea设置默认设置例如设置默认maven
- CentOS-6.7安装git
- 知其然知其所以然之——word2vector
- EasyUI的DataGrid中url参数返回数据格式
- angularJs中关于ng-class的三种使用方式说明
- Swift3.0语言教程使用字符串创建和初始化字符串
- 休闲小趣一一3Dmax“简易教程”——1.3 3Ds MAX 选择与移动物体(基本操作)
- wireshark简单过滤规则