Speex编解码在Android上实现

2024-05-27 12:08
文章标签 实现 android 编解码 speex

本文主要是介绍Speex编解码在Android上实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  以前在应用中使用到了Speex编解码,近来总结了一下Speex在Android上的实现。Speex是一套主要针对语音的开源免费,无专利保护的音频压缩格式。Speex工程着力于通过提供一个可以替代高性能语音编解码来降低语音应用输入门槛 。另外,相对于其它编解码,Speex也很适合网络应用,在网络应用上有着自己独特的优势。同时,Speex还是GNU工程的一部分,在改版的BSD协议中得到了很好的支持。Speex是基于CELP并且专门为码率在2-44kbps的语音压缩而设计的。Speex源码是基于c语音实现的(也有java实现,效率相对较低)。

  1、去Speex官网下载最新Speex源码。

  2、创建新的android工程,并创建jni文件夹。

  3、把speex源码目录下的libspeex和include目录及其子目录文件全部拷贝到$project/jni目录下。

  4、在jni目录下新增Android.mk文件,编辑内容如下:



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 :=\  
libspeex/bits.c \  
libspeex/buffer.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/fftwrap.c \  
libspeex/filterbank.c \  
libspeex/filters.c \  
libspeex/gain_table.c \  
libspeex/gain_table_lbr.c \  
libspeex/hexc_10_32_table.c \  
libspeex/hexc_table.c \  
libspeex/high_lsp_tables.c \  
libspeex/jitter.c \  
libspeex/kiss_fft.c \  
libspeex/kiss_fftr.c \  
libspeex/lpc.c \  
libspeex/lsp.c \  
libspeex/lsp_tables_nb.c \  
libspeex/ltp.c \  
libspeex/mdf.c \  
libspeex/modes.c \  
libspeex/modes_wb.c \  
libspeex/nb_celp.c \  
libspeex/preprocess.c \  
libspeex/quant_lsp.c \  
libspeex/resample.c \  
libspeex/sb_celp.c \  
libspeex/scal.c \  
libspeex/smallft.c \  
libspeex/speex.c \  
libspeex/speex_callbacks.c \  
libspeex/speex_header.c \  
libspeex/stereo.c \  
libspeex/vbr.c \  
libspeex/vq.c \  
libspeex/window.c \  
speex_jni.cpp \  


include $(BUILD_SHARED_LIBRARY)  

  5.在jni目录下新增Application.mk文件,编辑内容如下

  APP_ABI := armeabi armeabi-v7a   

  6.在$project/jni/include/speex/目录下新增speex_config_types.h文件,编辑内容如下



01.#ifndef __SPEEX_TYPES_H__    
02.#define __SPEEX_TYPES_H__    
03.typedef short spx_int16_t;    
04.typedef unsigned short spx_uint16_t;    
05.typedef int spx_int32_t;    
06.typedef unsigned int spx_uint32_t;    
07.#endif    

  7.创建JNI包装类speex_jni.cpp,用来调用Speex中的C代码函数,编辑内容如下



#include <jni.h>

#include <string.h>
#include <unistd.h>

#include <speex/speex.h>

staticint codec_open = 0;  

staticint dec_frame_size;  
staticint enc_frame_size;  

static SpeexBits ebits, dbits;  
void *enc_state;  
void *dec_state;  

static JavaVM *gJavaVM;  

extern"C"
JNIEXPORT jint JNICALL Java_com_trunkbow_speextest_Speex_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 Java_com_trunkbow_speextest_Speex_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);  
    }  
//env->GetShortArrayRegion(lin, offset, 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_trunkbow_speextest_Speex_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_trunkbow_speextest_Speex_getFrameSize  
    (JNIEnv *env, jobject obj) {  

if (!codec_open)  
return 0;  
return (jint)enc_frame_size;  

}  

extern"C"
JNIEXPORT void JNICALL Java_com_trunkbow_speextest_Speex_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);  
}  

  8.在Java层创建Speex工具类,内容如下:



package com.trunkbow.speextest;  

publicclass Speex {  
/* 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) 
     */
privatestaticfinalint DEFAULT_COMPRESSION = 8;     

    Speex() {    
    }    

publicvoid init() {    
        load();     
        open(DEFAULT_COMPRESSION);     
    }    

privatevoid load() {    
try {    
            System.loadLibrary("speex");    
        } catch (Throwable e) {    
            e.printStackTrace();    
        }    

    }    

publicnativeint open(int compression);    
publicnativeint getFrameSize();    
publicnativeint decode(byte encoded[], short lin[], int size);    
publicnativeint encode(short lin[], int offset, byte encoded[], int size);    
publicnativevoid close();    
}  

  9、使用cygwin编译,生成so文件。

这篇关于Speex编解码在Android上实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1007436

相关文章

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

Redis客户端连接机制的实现方案

《Redis客户端连接机制的实现方案》本文主要介绍了Redis客户端连接机制的实现方案,包括事件驱动模型、非阻塞I/O处理、连接池应用及配置优化,具有一定的参考价值,感兴趣的可以了解一下... 目录1. Redis连接模型概述2. 连接建立过程详解2.1 连php接初始化流程2.2 关键配置参数3. 最大连

Python实现网格交易策略的过程

《Python实现网格交易策略的过程》本文讲解Python网格交易策略,利用ccxt获取加密货币数据及backtrader回测,通过设定网格节点,低买高卖获利,适合震荡行情,下面跟我一起看看我们的第一... 网格交易是一种经典的量化交易策略,其核心思想是在价格上下预设多个“网格”,当价格触发特定网格时执行买

Android Paging 分页加载库使用实践

《AndroidPaging分页加载库使用实践》AndroidPaging库是Jetpack组件的一部分,它提供了一套完整的解决方案来处理大型数据集的分页加载,本文将深入探讨Paging库... 目录前言一、Paging 库概述二、Paging 3 核心组件1. PagingSource2. Pager3.

python设置环境变量路径实现过程

《python设置环境变量路径实现过程》本文介绍设置Python路径的多种方法:临时设置(Windows用`set`,Linux/macOS用`export`)、永久设置(系统属性或shell配置文件... 目录设置python路径的方法临时设置环境变量(适用于当前会话)永久设置环境变量(Windows系统

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、

PyCharm中配置PyQt的实现步骤

《PyCharm中配置PyQt的实现步骤》PyCharm是JetBrains推出的一款强大的PythonIDE,结合PyQt可以进行pythion高效开发桌面GUI应用程序,本文就来介绍一下PyCha... 目录1. 安装China编程PyQt1.PyQt 核心组件2. 基础 PyQt 应用程序结构3. 使用 Q