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文件。

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

  • 相关阅读:
    Java实现 LeetCode 136 只出现一次的数字
    Java实现 LeetCode 136 只出现一次的数字
    Java实现 LeetCode 136 只出现一次的数字
    Java实现 LeetCode 135 分发糖果
    Java实现 LeetCode 135 分发糖果
    Java实现 LeetCode 135 分发糖果
    Java实现 LeetCode 134 加油站
    Java实现 LeetCode 134 加油站
    Java实现 LeetCode 134 加油站
    Java实现 LeetCode 133 克隆图
  • 原文地址:https://www.cnblogs.com/jiayonghua/p/3763361.html
Copyright © 2011-2022 走看看