Android语音——speex编码解码(一)
2016-11-12 17:50
141 查看
Android中录音使用AudioRecord录音后的格式为pcm,要想播放需要转换格式,可以加入44字节的头转换为wav格式然后播放,但是我们要在网络上传输还是要把音频压缩一下,压缩为speex文件方便传输,节省流量,下面讲解怎样打speex的so库,和怎样使用speex在wav和spx文件之间相互转换。
1.在speex官网上下载speex源码 https://www.speex.org/downloads/
![](https://img-blog.csdn.net/20161112151223781)
2.得到speex-1.2rc2.tar.gz ,然后解压缩得到speex文件夹内容如图
![](https://img-blog.csdn.net/20161112152243771)
3.创建一个Android项目,命名为Speex,项目中新建jni目录,并把speex源码目录下的libspeex和include目录及其子目录文件全部拷贝到
![](https://img-blog.csdn.net/20161112152530678)
4.创建几个文件
在jni目录下新增Android.mk文件,复制如下内容(意思是编译speex_jni.cpp和libspeex下所有的c文件,有三个测试文件不用编译testenc_uwb.c、testenc_wb.c 、testenc.c )
在jni目录下增加Application.mk,复制内容如下(意思是编译所有平台下的so文件):
在jni/include/speex/目录下新增speex_config_types.h文件,复制内容如下:
在包com.speex.util中新建SpeexUtil类,复制以下内容(主要定义native方法)
在jni根目录下新建speex_jni.cpp实现刚才的native方法,复制内容:
新增完成后目录结构如下(共增加了5个文件):
![](https://img-blog.csdn.net/20161112163128597)
5.下面开始生成so库
使用ndk-build生成so文件,生成方法参考本文:HelloJni导入到Eclipse及命令行编译
编译完成,如图:
![](https://img-blog.csdn.net/20161112165936275)
刷新项目后,生成了obj文件夹:
![](https://img-blog.csdn.net/20161112170017744)
6.将Speex提供为jar包和so的形式供外部项目使用,使用时拷贝jar包到lib中,so拷贝到lib中对应的平台下
打开cmd,运行下图中命令将SpeexUtil.class打入jar包内
![](https://img-blog.csdn.net/20161112173834311)
最后附上源码和打包的jar和so库下载地址:
http://download.csdn.net/detail/jianiuqi/9683657
下一篇文件中将介绍怎样使用生成的jar完成wav转speex和speex转wav,并提供了使用示例源码下载(包括AS和Eclipse版本):
Android语音——speex编码解码(二)
1.在speex官网上下载speex源码 https://www.speex.org/downloads/
2.得到speex-1.2rc2.tar.gz ,然后解压缩得到speex文件夹内容如图
3.创建一个Android项目,命名为Speex,项目中新建jni目录,并把speex源码目录下的libspeex和include目录及其子目录文件全部拷贝到
$project/jni目录下,拷贝完成如下图:
4.创建几个文件
在jni目录下新增Android.mk文件,复制如下内容(意思是编译speex_jni.cpp和libspeex下所有的c文件,有三个测试文件不用编译testenc_uwb.c、testenc_wb.c 、testenc.c )
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libspeex LOCAL_CFLAGS = -DFIXED_POINT -DUSE_KISS_FFT -DEXPORT="" -UHAVE_CONFIG_H LOCAL_C_INCLUDES := $(LOCAL_PATH)/include #LOCAL_SRC_FILES := LOCAL_SRC_FILES := speex_jni.cpp \ ./libspeex/bits.c \ ./libspeex/cb_search.c \ ./libspeex/exc_10_16_table.c \ ./libspeex/exc_10_32_table.c \ ./libspeex/exc_20_32_table.c \ ./libspeex/exc_5_256_table.c \ ./libspeex/exc_5_64_table.c \ ./libspeex/exc_8_128_table.c \ ./libspeex/filters.c \ ./libspeex/gain_table_lbr.c \ ./libspeex/gain_table.c \ ./libspeex/hexc_10_32_table.c \ ./libspeex/hexc_table.c \ ./libspeex/high_lsp_tables.c \ ./libspeex/kiss_fft.c \ ./libspeex/kiss_fftr.c \ ./libspeex/lpc.c \ ./libspeex/lsp_tables_nb.c \ ./libspeex/lsp.c \ ./libspeex/ltp.c \ ./libspeex/modes_wb.c \ ./libspeex/modes.c \ ./libspeex/nb_celp.c \ ./libspeex/quant_lsp.c \ ./libspeex/sb_celp.c \ ./libspeex/smallft.c \ ./libspeex/speex_callbacks.c \ ./libspeex/speex_header.c \ ./libspeex/speex.c \ ./libspeex/stereo.c \ ./libspeex/vbr.c \ ./libspeex/vorbis_psy.c \ ./libspeex/vq.c \ ./libspeex/window.c \ include $(BUILD_SHARED_LIBRARY)
在jni目录下增加Application.mk,复制内容如下(意思是编译所有平台下的so文件):
APP_ABI := all
在jni/include/speex/目录下新增speex_config_types.h文件,复制内容如下:
#ifndef __SPEEX_TYPES_H__ #define __SPEEX_TYPES_H__ typedef short spx_int16_t; typedef unsigned short spx_uint16_t; typedef int spx_int32_t; typedef unsigned int spx_uint32_t; #endif
在包com.speex.util中新建SpeexUtil类,复制以下内容(主要定义native方法)
package com.speex.util; /** * * @author jxn * 2016年11月15日有更新,更改默认压缩比,并增加单例模式,重新打jar包 */ public class SpeexUtil { /* * quality 1 : 4kbps (very noticeable artifacts, usually intelligible) 2 : * 6kbps (very noticeable artifacts, good intelligibility) 4 : 8kbps * (noticeable artifacts sometimes) 6 : 11kpbs (artifacts usually only * noticeable with headphones) 8 : 15kbps (artifacts not usually noticeable) */ //设置为4时压缩比为1/16(与编解码密切相关) private static final int DEFAULT_COMPRESSION = 4; static { try { System.loadLibrary("speex"); } catch (Throwable e) { e.printStackTrace(); } } private static SpeexUtil speexUtil = null; SpeexUtil() { open(DEFAULT_COMPRESSION); } public static SpeexUtil getInstance(){ if (speexUtil == null) { synchronized (SpeexUtil.class) { if (speexUtil == null) { speexUtil = new SpeexUtil(); } } } return speexUtil; } public native int open(int compression); public native int getFrameSize(); public native int decode(byte encoded[], short lin[], int size); public native int encode(short lin[], int offset, byte encoded[], int size); public native void close(); }
在jni根目录下新建speex_jni.cpp实现刚才的native方法,复制内容:
#include <jni.h> #include <string.h> #include <unistd.h> #include <speex/speex.h> static int codec_open = 0; static int dec_frame_size; static int enc_frame_size; static SpeexBits ebits, dbits; void *enc_state; void *dec_state; static JavaVM *gJavaVM; extern "C" JNIEXPORT jint JNICALL Java_com_speex_util_SpeexUtil_open (JNIEnv *env, jobject obj, jint compression) { int tmp; if (codec_open++ != 0) return (jint)0; speex_bits_init(&ebits); speex_bits_init(&dbits); enc_state = speex_encoder_init(&speex_nb_mode); dec_state = speex_decoder_init(&speex_nb_mode); tmp = compression; speex_encoder_ctl(enc_state, SPEEX_SET_QUALITY, &tmp); speex_encoder_ctl(enc_state, SPEEX_GET_FRAME_SIZE, &enc_frame_size); speex_decoder_ctl(dec_state, SPEEX_GET_FRAME_SIZE, &dec_frame_size); return (jint)0; } extern "C" JNIEXPORT jint JNICALL Java_com_speex_util_SpeexUtil_encode (JNIEnv *env, jobject obj, jshortArray lin, jint offset, jbyteArray encoded, jint size) { jshort buffer[enc_frame_size]; jbyte output_buffer[enc_frame_size]; int nsamples = (size-1)/enc_frame_size + 1; int i, tot_bytes = 0; if (!codec_open) return 0; speex_bits_reset(&ebits); for (i = 0; i < nsamples; i++) { env->GetShortArrayRegion(lin, offset + i*enc_frame_size, enc_frame_size, buffer); speex_encode_int(enc_state, buffer, &ebits); } tot_bytes = speex_bits_write(&ebits, (char *)output_buffer, enc_frame_size); env->SetByteArrayRegion(encoded, 0, tot_bytes, output_buffer); return (jint)tot_bytes; } extern "C" JNIEXPORT jint JNICALL Java_com_speex_util_SpeexUtil_decode (JNIEnv *env, jobject obj, jbyteArray encoded, jshortArray lin, jint size) { jbyte buffer[dec_frame_size]; jshort output_buffer[dec_frame_size]; jsize encoded_length = size; if (!codec_open) return 0; env->GetByteArrayRegion(encoded, 0, encoded_length, buffer); speex_bits_read_from(&dbits, (char *)buffer, encoded_length); speex_decode_int(dec_state, &dbits, output_buffer); env->SetShortArrayRegion(lin, 0, dec_frame_size, output_buffer); return (jint)dec_frame_size; } extern "C" JNIEXPORT jint JNICALL Java_com_speex_util_SpeexUtil_getFrameSize (JNIEnv *env, jobject obj) { if (!codec_open) return 0; return (jint)enc_frame_size; } extern "C" JNIEXPORT void JNICALL Java_com_speex_util_SpeexUtil_close (JNIEnv *env, jobject obj) { if (--codec_open != 0) return; speex_bits_destroy(&ebits); speex_bits_destroy(&dbits); speex_decoder_destroy(dec_state); speex_encoder_destroy(enc_state); }
新增完成后目录结构如下(共增加了5个文件):
5.下面开始生成so库
使用ndk-build生成so文件,生成方法参考本文:HelloJni导入到Eclipse及命令行编译
编译完成,如图:
刷新项目后,生成了obj文件夹:
6.将Speex提供为jar包和so的形式供外部项目使用,使用时拷贝jar包到lib中,so拷贝到lib中对应的平台下
打开cmd,运行下图中命令将SpeexUtil.class打入jar包内
最后附上源码和打包的jar和so库下载地址:
http://download.csdn.net/detail/jianiuqi/9683657
下一篇文件中将介绍怎样使用生成的jar完成wav转speex和speex转wav,并提供了使用示例源码下载(包括AS和Eclipse版本):
Android语音——speex编码解码(二)
相关文章推荐
- Android语音——speex编码解码(二)
- Android语音文件speex编码解码(一)
- Android语音文件speex编码解码(二)
- 使用Android自带的TTS实现语音播报(电话号码)功能
- Android语音信息相关技术
- 【移动安全】HacktingTeam Android语音监控实践及分析
- Android 离线语音(讯飞语音)封装工具类
- Android中使用TTS(TextToSpeech)将文字转为语音
- Android TTS(TextToSpeech)语音输出与RecognizerIntent语音识别
- Android 高仿微信语音聊天页面高斯模糊效果
- Android 多媒体之实现语音聊天界面
- android---高德地图(5)导航界面(语音播报)实现
- 改进Android语音对讲系统的方法
- Android开发之语音听写及语音合成
- Android——科大讯飞语音集成
- Android中IM的语音处理简介及初步实现
- Android仿百度地图小度语音助手的贝塞尔曲线动画
- android 语音识别
- Android手机间语音通话使用webrtc消除回音
- Android ilbc 语音对话示范(三)程序流程