Unity 工具-Opus音频压缩(安卓篇)
2017-09-02 17:55
716 查看
现在很多游戏开始注重社交,因此语音成了游戏中不可或缺的部分。很多公司由于各种限制,可能使用第三方的SDK。虽然方便使用,但是费用挺高,而且不开源,不方便控制细节。
Opus编码器 是一个有损声音编码的格式,由互联网工程任务组(IETF)近来开发Opus 格式是一个开放格式,使用上没有任何专利或限制,应该算是Speex的升级吧,在压缩质量和效率上有了很大的提升。
具体的对比:官网对比说明
在Unity中使用Opus,首先要自己编译成对应Win、Android、IOS的支持库,网上关于Win和Android的网上有很多。我是自己写了简单的接口函数,然后分别对应编译成.dll、.so和.o,导入到Unity中用C#调用。(过去没有接触过编译,因此说的都是入门的,可能有些也不对,大神可以不用看下面的)
其中有几个坑:
Opus源码在Win有对应的解决方案,因此直接VS打开就可以,写完接口函数,直接编译就好,但是如果编译IOS,就需要自己新建工程,然后导入Opus源码,注意只导入C文件和头文件,其他的都不要导进去,并且所有的X86文件夹都不要导入,IOS只有ARM的CPU。
IOS必须在真机上测试,Unity中不能调用静态库。
安卓的是按照网上的教程,使用NDK编译,感觉很好用,写好MK,就不用管了,我只把接口函数写入,它会自动将以来的方法编译进去。
其中安卓的编译,参考 前人的经验,接口函数不同,需要写C#调用的,而不是JAVA
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_SRC_FILES := opusmain.cpp\ #封装接口opusmain.cpp
接口文件按照自己写的改,而且要写成可以C#访问的,而不是JAVA,网上的很多都只是Android使用,要自己写接口函数。
其中include celt_sources.mk include silk_sources.mk include opus_sources.mk为官方自带的MK,里面有需要的编译规则,cilt主要处理音乐,silk处理声音(skype开发)
4.配置Application.mk
5.接口函数
头文件opusmain.h
C++文件opusmain.cpp
编译过程很简单
进入到Opus文件夹,在里面打开命令行,输入ndk-build,就可以,他会自动找到MK文件,并按规则编译。
在生成Lib文件夹,在里面就能找到.so文件
安卓的先到这,IOS和Win的,以及Unity怎么使用,在下篇博客
Opus编码器 是一个有损声音编码的格式,由互联网工程任务组(IETF)近来开发Opus 格式是一个开放格式,使用上没有任何专利或限制,应该算是Speex的升级吧,在压缩质量和效率上有了很大的提升。
具体的对比:官网对比说明
在Unity中使用Opus,首先要自己编译成对应Win、Android、IOS的支持库,网上关于Win和Android的网上有很多。我是自己写了简单的接口函数,然后分别对应编译成.dll、.so和.o,导入到Unity中用C#调用。(过去没有接触过编译,因此说的都是入门的,可能有些也不对,大神可以不用看下面的)
其中有几个坑:
Opus源码在Win有对应的解决方案,因此直接VS打开就可以,写完接口函数,直接编译就好,但是如果编译IOS,就需要自己新建工程,然后导入Opus源码,注意只导入C文件和头文件,其他的都不要导进去,并且所有的X86文件夹都不要导入,IOS只有ARM的CPU。
IOS必须在真机上测试,Unity中不能调用静态库。
安卓的是按照网上的教程,使用NDK编译,感觉很好用,写好MK,就不用管了,我只把接口函数写入,它会自动将以来的方法编译进去。
其中安卓的编译,参考 前人的经验,接口函数不同,需要写C#调用的,而不是JAVA
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_SRC_FILES := opusmain.cpp\ #封装接口opusmain.cpp
接口文件按照自己写的改,而且要写成可以C#访问的,而不是JAVA,网上的很多都只是Android使用,要自己写接口函数。
LOCAL_PATH := $(call my-dir) #加载当前路径 include $(CLEAR_VARS) include celt_sources.mk #加载celt 所有.c的 mk include silk_sources.mk #加载silk 所有.c 的mk include opus_sources.mk #加载opus 所有.c 的mk MY_MODULE_DIR := newopus #库的名称 LOCAL_MODULE := $(MY_MODULE_DIR) SILK_SOURCES += $(SILK_SOURCES_FIXED) #编译的源代码.c CELT_SOURCES += $(CELT_SOURCES_ARM) SILK_SOURCES += $(SILK_SOURCES_ARM) LOCAL_SRC_FILES := opusmain.cpp\ #封装接口opusmain.cpp $(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=64 LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT=1 -DDISABLE_FLOAT_API -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -O3 -fno-math-errno LOCAL_CPPFLAGS := -DBSD=1 LOCAL_CPPFLAGS += -ffast-math -O3 -funroll-loops include $(BUILD_SHARED_LIBRARY) #编译动态库设置
其中include celt_sources.mk include silk_sources.mk include opus_sources.mk为官方自带的MK,里面有需要的编译规则,cilt主要处理音乐,silk处理声音(skype开发)
4.配置Application.mk
APP_ABI := armeabi armeabi-v7a #编译运行的系统,平台 NDK_TOOLCHAIN_VERSION=4.9 #指定交叉编译器 APP_PLATFORM := android-19 #设定ndk编译的版本
5.接口函数
头文件opusmain.h
int frame_size; int channels = 1; opus_int32 opus_num; opus_int32 pcm_num; float* pcm_dataFloat_encoder = NULL; opus_int16* pcm_dataInt_encoder = NULL; unsigned char* opus_dataInt_decoder = NULL; unsigned char* opus_dataFloat_decoder = NULL; OpusEncoder *enc = NULL; OpusDecoder *dec = NULL; int error; //必须带有extern "C",否则在Unity中找不到以下方法 extern "C" { int nMyOpus; int fnMyOpus(void); void opusEncoderInit(int Fs, int _channels); void opusEncoderSet(int _frame_size, bool isFloat, int quality, int signal); void opusDecoderInit(int Fs, int _channels, int max_len, bool isFloat); int opusEncoder(opus_int16 *encoder_insrc, int in_offset, unsigned char *encoder_out, int max_len); int opusDecoder(int len, unsigned char *decoder_insrc, int in_offset, opus_int16 *decoder_out); int opusEncoderFloat(float *encoder_insrc, int in_offset, unsigned char *encoder_out, int max_len); int opusDecoderFloat(int len, unsigned char *decoder_insrc, int in_offset, float *decoder_out); void opusEncoderDispose(); void opusDecoderDispose(); }
C++文件opusmain.cpp
#include <jni.h> #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include "arch.h" #include "opus_multistream.h" #include "opus.h" #include "opusmain.h" #include "../src/opus_private.h" #ifdef VALGRIND #include <valgrind/memcheck.h> #define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y)) #define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y)) #endif // 这是导出函数的一个示例。这个函数没逻辑,就是测试Unity是否能够连接到静态库 int MyOpus() { return 2; } OpusEncoder* OpusEncoderInit(int Fs) { OpusEncoder *enc = NULL; int complexity = 1; int signal = OPUS_SIGNAL_VOICE; int application = OPUS_APPLICATION_AUDIO; int bitrate_bps = 32000; int bandwidth = OPUS_AUTO; int use_vbr = 1; int cvbr = 0; int packet_loss_perc = 0; enc = opus_encoder_create(Fs, channels, application, &error); opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal)); opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps)); opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth)); opus_encoder_ctl(enc, OPUS_SET_VBR(use_vbr)); opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(cvbr)); opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity)); opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc)); return enc; } void OpusEncoderSet(OpusEncoder *enc, int complexity, int signal, int bitrate, int frame_size, int cvbr) { opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal)); opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate)); opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity)); opus_encoder_ctl(enc, OPUS_SET_VBR(1 - cvbr)); opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(cvbr)); } OpusDecoder* OpusDecoderInit(int Fs) { OpusDecoder *dec = opus_decoder_create(Fs, channels, &error); return dec; } int OpusEncoderInt(OpusEncoder *enc, int frame_size, opus_int16 *encoder_insrc, unsigned char *encoder_out, int max_len) { opus_int32 opus_num = opus_encode( enc, encoder_insrc, frame_size, encoder_out, max_len); return opus_num; } int OpusDecoderInt(OpusDecoder *dec, int frame_size, int len, unsigned char *decoder_insrc, opus_int16 *decoder_out) { opus_int32 pcm_num = opus_decode( dec, decoder_insrc, len, decoder_out, frame_size, 0); return pcm_num; }
编译过程很简单
进入到Opus文件夹,在里面打开命令行,输入ndk-build,就可以,他会自动找到MK文件,并按规则编译。
在生成Lib文件夹,在里面就能找到.so文件
安卓的先到这,IOS和Win的,以及Unity怎么使用,在下篇博客
相关文章推荐
- Unity 工具-Opus音频压缩(Win篇)
- unity 写批量打包工具时遇到的一个问题
- Unity -- Bezier曲线(创建/编辑工具)
- Unity编辑器工具错误
- 如何在Unity编辑器中添加你自己的工具
- 帮同学做的把T1图像转成TXT格式用于unity 3d输入的小工具
- unity 实现另一个unity软件的安装工具(4)——unity调用外部程序,三种路径方式
- Unity外部工具常见问题
- Unity的Visual Studio工具入门
- Unity非运行模式下实现动画播放/回退工具
- Unity自动打包工具
- unity连接数据库工具
- 十款Unity相关开发插件和工具
- Unity 游戏框架搭建 (十一) 简易AssetBundle打包工具(一)
- 可以快速保存、访问和粘贴文本片段的Unity漂亮工具
- Unity日志工具——封装,跳转
- Unity编辑器 - 资源批处理工具基类
- Unity 自制工具:Point。方便标记出生点或巡逻点等功能。
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- unity 开源插件 解析psd文件,一键生成ugui面板工具