android ios opus语音编码压缩库编译

来源:互联网 发布:爱情观知乎 编辑:程序博客网 时间:2024/05/16 06:50
据说Opus 比speex库,aac各方面性能更好,也很适合做网络语音通话。

采样率 :
音频取样频率, 指每秒钟取得声音样本的次数。采样频率越高,声音的质量也就越好,声音的还原也就越真实,但同时它占的资源比较多。一般采样率有 8000HZ 16000HZ 44100HZ。
比特率:
每秒的传输速率(位速, 也叫比特率)。如256kbps 或256000bps, 其中的 b 是 bit, ps 是每秒的意思,表示每秒256000bit的容量。
8bit=1Byte
帧:
帧记录了一个声音单元,其长度为样本长度(采样位数)和通道数的乘积。采样率X通道数X采样位数=8000X1X16=128000bit=16000Byte。
Opus压缩的声音需要pcm编码.

Android Opus编译过程
编译好下载地址:http://download.csdn.net/download/undiif123/9854940

1.打开android studio,点击sdk-manager->android sdk勾选红色箭头进行安装ndk等库,ndk需要设置一下环境变量,设置后cmd就可以直接编译了。

这里写图片描述

2.下载Opus_1.1.4 解压后把本文件名命名jni,celt_headers.mk,celt_sources.mk,opus_headers.mk,opus_sources.mk,silk_headers.mk,silk_sources.mk 把这mk放在jni同级目录中
3.配置android.mk

LOCAL_PATH := $(call my-dir)  #加载当前路径include $(CLEAR_VARS)include celt_sources.mk   #加载celt 所有.c的 mkinclude silk_sources.mk  #加载silk 所有.c 的mkinclude opus_sources.mk #加载opus 所有.c 的mkMY_MODULE_DIR       := newopus  #库的名称LOCAL_MODULE        := $(MY_MODULE_DIR)SILK_SOURCES += $(SILK_SOURCES_FIXED)#编译的源代码.cCELT_SOURCES += $(CELT_SOURCES_ARM)SILK_SOURCES += $(SILK_SOURCES_ARM)LOCAL_SRC_FILES     := opusmain.c\   #封装接口opusmain.c$(CELT_SOURCES) $(SILK_SOURCES) $(OPUS_SOURCES)LOCAL_LDLIBS        := -lm –llog  #加载系统的库 日志库LOCAL_C_INCLUDES    := \  #包含头文件$(LOCAL_PATH)/include \$(LOCAL_PATH)/silk \$(LOCAL_PATH)/silk/fixed \$(LOCAL_PATH)/celt#附加编译选项LOCAL_CFLAGS        := -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64LOCAL_CFLAGS        += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT=1 -DDISABLE_FLOAT_API -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -O3 -fno-math-errnoLOCAL_CPPFLAGS      := -DBSD=1LOCAL_CPPFLAGS      += -ffast-math -O3 -funroll-loopsinclude $(BUILD_SHARED_LIBRARY)  #编译动态库设置

4.配置Application.mk

APP_ABI := armeabi armeabi-v7a  #编译运行的系统,平台NDK_TOOLCHAIN_VERSION=4.9 #指定交叉编译器APP_PLATFORM := android-19   #设定ndk编译的版本

5.以上配置完编译
这里写图片描述
Cmd 到项目中 有jni文件夹 进行ndk-build编译就ok了 把libopus复制到项目libs对应的armeabi armeabi-v7a 目录下

封装接口源代码:

Opusmain.c#include <jni.h>#include <string.h>#include <android/log.h>#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <stdio.h>#include <stdlib.h>#include <limits.h>#include <stdint.h>#include <math.h>#include <string.h>#include <time.h>#if (!defined WIN32 && !defined _WIN32) || defined(__MINGW32__)#include <unistd.h>#else#include <process.h>#define getpid _getpid#endif#include "opus_multistream.h"#include "opus.h"#include "../src/opus_private.h"#define MAX_PACKET (1500)#define SAMPLES (48000*30)#define SSAMPLES (SAMPLES/3)#define MAX_FRAME_SAMP (5760)//每采集一帧大小为160short=320个字节//帧的计算,例如 采样率8000 单通道 采样位数16bit//1秒采集到数据8000X1X16=16000Byte//网络语音传输20ms一次 也就是说1秒发50次320Byte的包 320Byte=160Short//采集一次是160Short#define FRAME_SIZE 160#define SAMPLE_RATE 8000#define CHANNELS 1#define APPLICATION OPUS_APPLICATION_AUDIO//参数调整压缩倍数可设置7000 声音还能正常,压缩率160short 压缩成18short#define BITRATE 8000#define MAX_FRAME_SIZE 6*960#define MAX_PACKET_SIZE (3*1276)OpusEncoder *encoder;OpusDecoder *decoder;int bandwidth = OPUS_AUTO;int use_vbr = 0;int cvbr=1;int complexity = 4;int packet_loss_perc=0;//初始化语音//com_gauss_ opus _encode java层的包名,Opus类名,open函数名 这样定义好java就可以直接调用了jint Java_com_gauss_opus_encode_Speex_open(JNIEnv *env,jobject thiz,jint compression){   int err;    encoder = opus_encoder_create(SAMPLE_RATE, CHANNELS, APPLICATION, &err);   if (err<0)   {      return 0;   }   err = opus_encoder_ctl(encoder, OPUS_SET_BITRATE(BITRATE));   if (err<0)   {            return 0;   }   opus_encoder_ctl(encoder, OPUS_SET_BANDWIDTH(bandwidth));   opus_encoder_ctl(encoder, OPUS_SET_VBR(use_vbr));   opus_encoder_ctl(encoder, OPUS_SET_VBR_CONSTRAINT(cvbr));  opus_encoder_ctl(encoder, OPUS_SET_COMPLEXITY(compression));          opus_encoder_ctl(encoder,   OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc));   decoder = opus_decoder_create(SAMPLE_RATE, CHANNELS, &err);   if (err<0)   {            return 0;   }   return 1;}JNIEXPORTjint Java_com_gauss_opus_encode_Opus_getFrameSize(JNIEnv *env,jobject thiz){    return  FRAME_SIZE;}//压缩JNIEXPORTjint Java_com_gauss_opus_encode_Opus_encode(JNIEnv *env,jobject thiz,                                                  jshortArray lin, jint offset, jbyteArray encoded, jint size){    int err;    int i;    int nbBytes;    unsigned short cbits[480];    unsigned short out[160];    if(encoder == NULL){        return 0;    }  //读取参数 数组    (*env)->GetShortArrayRegion(env,lin,offset,size,out);nbBytes = opus_encode(encoder,out , size, cbits, 480);////设定压缩完的数据到数组中    (*env)->SetByteArrayRegion(env,encoded, 0, nbBytes, (jshort*)cbits);    return nbBytes;}//解压JNIEXPORTjint Java_com_gauss_opus_encode_Opus_decode(JNIEnv *env,jobject thiz,                                                       jbyteArray encoded, jshortArray lin, int size){    int err;    int i;    int frame_size;    int nbBytes;    unsigned char cbits[MAX_PACKET_SIZE];    unsigned short out[160];    unsigned short deout[160];    if(decoder == NULL){        return 0;    }    (*env)->GetByteArrayRegion(env, encoded,0,size,out);    frame_size = opus_decode(decoder, out, size, deout, MAX_FRAME_SIZE, 0);    if(frame_size <0){        return 0;    }    int nSize = frame_size*CHANNELS;    (*env)->SetShortArrayRegion(env,lin, 0, nSize, (jshort*)deout);    return nSize;}//释放语音对象JNIEXPORTvoid Java_com_gauss_opus_encode_Opus_close(JNIEnv *env,jobject thiz){  if(encoder !=NULL){   opus_encoder_destroy(encoder);  } if(encoder !=NULL){  opus_decoder_destroy(decoder);  }}

IOS编译

1.使用build-libopus.sh 脚本编译,修改一下参数
VERSION=1.1.4 #opus库的版本
SDKVERSION=”10.3” #ios sdk版本
MINIOSVERSION=”8.0” #最低版本8.0
2.然后使用终端编译build-libopus.sh
3.然后把libopus.a 和include 加入工程中。

#import "OpusCode1.h"@implementation OpusCode1- (id)init {    if (self = [super init]) {        codecOpenedTimes = 0;    }    return self;}/* quality value 1 ~ 10 */#define BITRATE 8000#define MAX_FRAME_SIZE 6*960- (void)open:(int)quality {    if ((quality < 1) || (quality > 10)) {        return;    }    if (codecOpenedTimes++ != 0) {        return;    }    else {        encodeFrameSize = 160;        decodeFrameSize = 160;        int bandwidth = OPUS_AUTO;        int use_vbr = 0;        int cvbr=1;        int packet_loss_perc=0;        //opus        int err;        encoder = opus_encoder_create(8000, 1, OPUS_APPLICATION_AUDIO, &err);        err = opus_encoder_ctl(encoder, OPUS_SET_BITRATE(BITRATE));        opus_encoder_ctl(encoder, OPUS_SET_BANDWIDTH(bandwidth));        opus_encoder_ctl(encoder, OPUS_SET_VBR(use_vbr));        opus_encoder_ctl(encoder, OPUS_SET_VBR_CONSTRAINT(cvbr));        opus_encoder_ctl(encoder, OPUS_SET_COMPLEXITY(quality));        opus_encoder_ctl(encoder, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc));        decoder = opus_decoder_create(8000, 1, &err);    }}- (NSData *)encode:(short *)pcmBuffer length:(int)lengthOfShorts {    if (codecOpenedTimes == 0) {        return nil;    }    //opus    int nbBytes;    unsigned short cbits[480];    NSMutableData *decodedData = [NSMutableData dataWithCapacity:20];    short input_frame[encodeFrameSize];    memset((Byte*)input_frame,0,encodeFrameSize*2);    memcpy(input_frame, pcmBuffer, encodeFrameSize * sizeof(short));    nbBytes = opus_encode(encoder, input_frame, encodeFrameSize, cbits, 480);    [decodedData appendBytes:cbits length:nbBytes];    return decodedData;}- (int)decode:(unsigned char *)encodedBytes length:(int)lengthOfBytes output:(short *)decoded {    if ( ! codecOpenedTimes)        return 0;    opus_int16 out[MAX_FRAME_SIZE];    char cbits[200];    memcpy(cbits, encodedBytes, lengthOfBytes);    int frame_size;    frame_size = opus_decode(decoder, (short*)encodedBytes, lengthOfBytes, decoded, MAX_FRAME_SIZE, 0);    return decodeFrameSize;}- (void)close {    if (--codecOpenedTimes != 0) {        return;    }    if(encoder !=NULL){    opus_encoder_destroy(encoder);    }    if(decoder !=NULL){    opus_decoder_destroy(decoder);    }}- (void)dealloc {    [self close];#if !__has_feature(objc_arc)//    [super dealloc];#endif}@end
原创粉丝点击