zoukankan      html  css  js  c++  java
  • Speex for Android

    在Android开发中,需要录音并发送到对方设备上。这时问题来了,手机常会是GPRS、3G等方式上网,所以节省流量是非常关键的,使用Speex来压缩音频文件,可以将音频压文件小数倍。

    1.去Speex官网下载最新Speex源码

    2.创建一个新的应用(我创建的应用名为Audio),并创建一个jni目录($project/jni)。

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

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

     

    [plain] view plaincopy
     
    1. LOCAL_PATH := $(call my-dir) 
    2.  
    3.  
    4. include $(CLEAR_VARS) 
    5.   
    6. LOCAL_MODULE    := libspeex 
    7. LOCAL_CFLAGS = -DFIXED_POINT -DUSE_KISS_FFT -DEXPORT="" -UHAVE_CONFIG_H 
    8. LOCAL_C_INCLUDES := $(LOCAL_PATH)/include 
    9.   
    10. LOCAL_SRC_FILES :=   
    11. ./speex_jni.cpp  
    12. ./libspeex/bits.c  
    13. ./libspeex/buffer.c  
    14. ./libspeex/cb_search.c  
    15. ./libspeex/exc_10_16_table.c  
    16. ./libspeex/exc_10_32_table.c  
    17. ./libspeex/exc_20_32_table.c  
    18. ./libspeex/exc_5_256_table.c  
    19. ./libspeex/exc_5_64_table.c  
    20. ./libspeex/exc_8_128_table.c  
    21. ./libspeex/fftwrap.c  
    22. ./libspeex/filterbank.c  
    23. ./libspeex/filters.c  
    24. ./libspeex/gain_table.c  
    25. ./libspeex/gain_table_lbr.c  
    26. ./libspeex/hexc_10_32_table.c  
    27. ./libspeex/hexc_table.c  
    28. ./libspeex/high_lsp_tables.c  
    29. ./libspeex/jitter.c  
    30. ./libspeex/kiss_fft.c  
    31. ./libspeex/kiss_fftr.c  
    32. ./libspeex/lpc.c  
    33. ./libspeex/lsp.c  
    34. ./libspeex/lsp_tables_nb.c  
    35. ./libspeex/ltp.c  
    36. ./libspeex/mdf.c  
    37. ./libspeex/modes.c  
    38. ./libspeex/modes_wb.c  
    39. ./libspeex/nb_celp.c  
    40. ./libspeex/preprocess.c  
    41. ./libspeex/quant_lsp.c  
    42. ./libspeex/resample.c  
    43. ./libspeex/sb_celp.c  
    44. ./libspeex/scal.c  
    45. ./libspeex/smallft.c  
    46. ./libspeex/speex.c  
    47. ./libspeex/speex_callbacks.c  
    48. ./libspeex/speex_header.c  
    49. ./libspeex/stereo.c  
    50. ./libspeex/vbr.c  
    51. ./libspeex/vq.c  
    52. ./libspeex/window.c 
    53.   
    54. include $(BUILD_SHARED_LIBRARY) 


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

     

     

    [plain] view plaincopy
     
    1. APP_ABI := armeabi armeabi-v7a 


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

     

     

    [cpp] view plaincopy
     
    1. #ifndef __SPEEX_TYPES_H__ 
    2. #define __SPEEX_TYPES_H__ 
    3. typedefshort spx_int16_t; 
    4. typedef unsigned short spx_uint16_t; 
    5. typedefint spx_int32_t; 
    6. typedef unsigned int spx_uint32_t; 
    7. #endif 

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

     

    [cpp] view plaincopy
     
    1. #include <jni.h> 
    2.  
    3. #include <string.h> 
    4. #include <unistd.h> 
    5.  
    6. #include <speex/speex.h> 
    7.  
    8. staticint codec_open = 0; 
    9.  
    10. staticint dec_frame_size; 
    11. staticint enc_frame_size; 
    12.  
    13. static SpeexBits ebits, dbits; 
    14. void *enc_state; 
    15. void *dec_state; 
    16.  
    17. static JavaVM *gJavaVM; 
    18.  
    19. extern"C" 
    20. JNIEXPORT jint JNICALL Java_com_audio_Speex_open 
    21.   (JNIEnv *env, jobject obj, jint compression) { 
    22.     int tmp; 
    23.  
    24.     if (codec_open++ != 0) 
    25.         return (jint)0; 
    26.  
    27.     speex_bits_init(&ebits); 
    28.     speex_bits_init(&dbits); 
    29.  
    30.     enc_state = speex_encoder_init(&speex_nb_mode); 
    31.     dec_state = speex_decoder_init(&speex_nb_mode); 
    32.     tmp = compression; 
    33.     speex_encoder_ctl(enc_state, SPEEX_SET_QUALITY, &tmp); 
    34.     speex_encoder_ctl(enc_state, SPEEX_GET_FRAME_SIZE, &enc_frame_size); 
    35.     speex_decoder_ctl(dec_state, SPEEX_GET_FRAME_SIZE, &dec_frame_size); 
    36.  
    37.     return (jint)0; 
    38.  
    39. extern"C" 
    40. JNIEXPORT jint Java_com_audio_Speex_encode 
    41.     (JNIEnv *env, jobject obj, jshortArray lin, jint offset, jbyteArray encoded, jint size) { 
    42.  
    43.         jshort buffer[enc_frame_size]; 
    44.         jbyte output_buffer[enc_frame_size]; 
    45.     int nsamples = (size-1)/enc_frame_size + 1; 
    46.     int i, tot_bytes = 0; 
    47.  
    48.     if (!codec_open) 
    49.         return 0; 
    50.  
    51.     speex_bits_reset(&ebits); 
    52.  
    53.     for (i = 0; i < nsamples; i++) { 
    54.         env->GetShortArrayRegion(lin, offset + i*enc_frame_size, enc_frame_size, buffer); 
    55.         speex_encode_int(enc_state, buffer, &ebits); 
    56.     } 
    57.     //env->GetShortArrayRegion(lin, offset, enc_frame_size, buffer); 
    58.     //speex_encode_int(enc_state, buffer, &ebits); 
    59.  
    60.     tot_bytes = speex_bits_write(&ebits, (char *)output_buffer, 
    61.                      enc_frame_size); 
    62.     env->SetByteArrayRegion(encoded, 0, tot_bytes, 
    63.                 output_buffer); 
    64.  
    65.         return (jint)tot_bytes; 
    66.  
    67. extern"C" 
    68. JNIEXPORT jint JNICALL Java_com_audio_Speex_decode 
    69.     (JNIEnv *env, jobject obj, jbyteArray encoded, jshortArray lin, jint size) { 
    70.  
    71.         jbyte buffer[dec_frame_size]; 
    72.         jshort output_buffer[dec_frame_size]; 
    73.         jsize encoded_length = size; 
    74.  
    75.     if (!codec_open) 
    76.         return 0; 
    77.  
    78.     env->GetByteArrayRegion(encoded, 0, encoded_length, buffer); 
    79.     speex_bits_read_from(&dbits, (char *)buffer, encoded_length); 
    80.     speex_decode_int(dec_state, &dbits, output_buffer); 
    81.     env->SetShortArrayRegion(lin, 0, dec_frame_size, 
    82.                  output_buffer); 
    83.  
    84.     return (jint)dec_frame_size; 
    85.  
    86. extern"C" 
    87. JNIEXPORT jint JNICALL Java_com_audio_getFrameSize 
    88.     (JNIEnv *env, jobject obj) { 
    89.  
    90.     if (!codec_open) 
    91.         return 0; 
    92.     return (jint)enc_frame_size; 
    93.  
    94.  
    95. extern"C" 
    96. JNIEXPORT void JNICALL Java_com_audio_Speex_close 
    97.     (JNIEnv *env, jobject obj) { 
    98.  
    99.     if (--codec_open != 0) 
    100.         return
    101.  
    102.     speex_bits_destroy(&ebits); 
    103.     speex_bits_destroy(&dbits); 
    104.     speex_decoder_destroy(dec_state); 
    105.     speex_encoder_destroy(enc_state); 


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

     

     

    [java] view plaincopy
     
    1. package com.audio; 
    2.  
    3. class Speex  { 
    4.  
    5.     /* quality
    6.      * 1 : 4kbps (very noticeable artifacts, usually intelligible)
    7.      * 2 : 6kbps (very noticeable artifacts, good intelligibility)
    8.      * 4 : 8kbps (noticeable artifacts sometimes)
    9.      * 6 : 11kpbs (artifacts usually only noticeable with headphones)
    10.      * 8 : 15kbps (artifacts not usually noticeable)
    11.      */ 
    12.     privatestaticfinalint DEFAULT_COMPRESSION = 8
    13.  
    14.     Speex() { 
    15.     } 
    16.  
    17.     publicvoid init() { 
    18.         load();  
    19.         open(DEFAULT_COMPRESSION); 
    20.     } 
    21.      
    22.     privatevoid load() { 
    23.         try
    24.             System.loadLibrary("speex"); 
    25.         } catch (Throwable e) { 
    26.             e.printStackTrace(); 
    27.         } 
    28.  
    29.     } 
    30.  
    31.     publicnativeint open(int compression); 
    32.     publicnativeint getFrameSize(); 
    33.     publicnativeint decode(byte encoded[], short lin[], int size); 
    34.     publicnativeint encode(short lin[], int offset, byte encoded[], int size); 
    35.     publicnativevoid close(); 
    36.      

    9.打开cygwin工具,切换到项目目录(我项目是在F:workspaceAudio),输入$NDK/ndk-build

    cygwin工具的安装与配置,可以看这篇文章——使用NDK与环境搭建

     

     

    会在项目中生成libs目录和libspeex.so文件,这就是Speex类中System.loadLibrary("speex");代码引用的,系统会根据操作系统由"speex"找到对应的动态库libspeex.so,Windows下是.dll文件,linux下是.so文件。

    当前,我的项目结构如下图

  • 相关阅读:
    RabbitMQ 内存控制 硬盘控制
    Flannel和Docker网络不通定位问题
    kafka集群扩容后的topic分区迁移
    CLOSE_WAIT状态的原因与解决方法
    搭建Harbor企业级docker仓库
    Redis哨兵模式主从持久化问题解决
    mysql杂谈(爬坑,解惑,总结....)
    Linux的信号量(semaphore)与互斥(mutex)
    SIP协议的传输层原理&报文解析(解读rfc3581)(待排版) && opensips
    SIP协议的传输层原理&报文解析(解读RFC3261)(待排版)&&启动
  • 原文地址:https://www.cnblogs.com/jiayonghua/p/3763361.html
Copyright © 2011-2022 走看看