首先配置Android Studio NDK以及下载Speex源码放入main/cpp/speex目录
在cpp目录下更改根CMakeList.tet文件:
一下是包含子目录得形式,
#指定需要CMAKE的最小版本
cmake_minimum_required(VERSION 3.4.1)
#C 的编译选项是 CMAKE_C_FLAGS
# 指定编译参数,可选
SET(CMAKE_CXX_FLAGS "-Wno-error=format-security -Wno-error=pointer-sign")
#设置生成的so动态库最后输出的路径
#set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
#设置头文件搜索路径(和此txt同个路径的头文件无需设置),可选
#INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/common)
#指定用到的系统库或者NDK库或者第三方库的搜索路径,可选。
#LINK_DIRECTORIES(/usr/local/lib)
#添加子目录,将会调用子目录中的CMakeLists.txt
ADD_SUBDIRECTORY(speex)
在cpp/speex增加子文件:
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html
# Sets the minimum version of CMake required to build the native library.
cmake_minimum_required(VERSION 3.4.1)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
set(CMAKE_C_FLAGS "-DFIXED_POINT -DUSE_KISS_FFT -DEXPORT="" -UHAVE_CONFIG_H")
add_library( # Sets the name of the library.
speex-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
speex_jni.cpp
./libspeex/bits.c
./libspeex/cb_search.c
./libspeex/buffer.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_lbr.c
./libspeex/gain_table.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_tables_nb.c
./libspeex/lsp.c
./libspeex/ltp.c
./libspeex/mdf.c
./libspeex/modes_wb.c
./libspeex/modes.c
./libspeex/nb_celp.c
./libspeex/preprocess.c
./libspeex/quant_lsp.c
./libspeex/sb_celp.c
./libspeex/scal.c
./libspeex/smallft.c
./libspeex/speex_callbacks.c
./libspeex/speex_header.c
./libspeex/speex.c
./libspeex/stereo.c
./libspeex/vbr.c
./libspeex/vorbis_psy.c
./libspeex/vq.c
./libspeex/window.c)
#target_include_directories(speex-lib
# PRIVATE
# /include)
include_directories(include)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.
target_link_libraries( # Specifies the target library.
speex-lib
# Links the target library to the log library
# included in the NDK.
${log-lib})
在gradle下:
defaultConfig {
...
externalNativeBuild {
cmake {
cppFlags "-std=c++11 -frtti"
abiFilters 'armeabi-v7a', "arm64-v8a", 'x86', 'x86_64'
arguments "-DANDROID_TOOLCHAIN=clang", "-DANDROID_STL=c++_static"
}
}
}
android {
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
}
若使用Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS :=-llog
LOCAL_MODULE := libspeex
LOCAL_CFLAGS = -DFIXED_POINT -DUSE_KISS_FFT -DEXPORT="" -UHAVE_CONFIG_H
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_SRC_FILES := speex_jni.cpp \
./libspeex/bits.c \
./libspeex/cb_search.c \
./libspeex/buffer.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_lbr.c \
./libspeex/gain_table.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_tables_nb.c \
./libspeex/lsp.c \
./libspeex/ltp.c \
./libspeex/mdf.c \
./libspeex/modes_wb.c \
./libspeex/modes.c \
./libspeex/nb_celp.c \
./libspeex/preprocess.c \
./libspeex/quant_lsp.c \
./libspeex/sb_celp.c \
./libspeex/scal.c \
./libspeex/smallft.c \
./libspeex/speex_callbacks.c \
./libspeex/speex_header.c \
./libspeex/speex.c \
./libspeex/stereo.c \
./libspeex/vbr.c \
./libspeex/vorbis_psy.c \
./libspeex/vq.c \
./libspeex/window.c \
include $(BUILD_SHARED_LIBRARY)
application.mk
APP_ABI := armeabi
gradle也不一样:
android{
externalNativeBuild {
ndkBuild {
path 'src/main/cpp/Android.mk'
}
}
}
speex_jni.cpp
#include <jni.h>
#include <string.h>
#include <unistd.h>
#include <speex/speex.h>
#include<Android/log.h>
static int codec_open = 0;
static int dec_frame_size;
static int enc_frame_size;
static SpeexBits ebits, dbits;
void *enc_state;
void *dec_state;
static JavaVM *gJavaVM;
#define TAG "JNI" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG ,__VA_ARGS__) // 定义LOGD类型
extern "C"
JNIEXPORT jint JNICALL Java_包名_NativeCodec_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;
}
float encoder_input[160];
extern "C"
JNIEXPORT jint Java_包名_NativeCodec_encode
(JNIEnv *env, jobject obj, jshortArray lin, jint offset, jbyteArray encoded, jint size) {
jshort buffer[enc_frame_size];
jbyte output_buffer[20];
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_包名_NativeCodec_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;
speex_bits_reset(&dbits);
env->GetByteArrayRegion(encoded, 0, encoded_length, buffer);
speex_bits_read_from(&dbits, (char *)buffer, encoded_length);
// speex_decode_int(dec_state, &dbits, output_buffer);
float decoder_output[dec_frame_size];
speex_decode(dec_state, &dbits, decoder_output);
for (int i = 0; i < dec_frame_size; i++)
{
output_buffer[i] = decoder_output[i];
}
env->SetShortArrayRegion(lin, 0, dec_frame_size,
output_buffer);
return (jint)dec_frame_size;
}
extern "C"
JNIEXPORT jint JNICALL Java_包名_NativeCodec_getFrameSize
(JNIEnv *env, jobject obj) {
if (!codec_open)
return 0;
return (jint)enc_frame_size;
}
extern "C"
JNIEXPORT void JNICALL Java_包名_NativeCodec_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);
}
public native int open(int compression); public native int getFrameSize(); public native int decode(byte encoded[], short lin[], int size); public native int encode(short lin[], int offset, byte encoded[], int size); public native void close();
解码参数 1 encodedData, 编码数据 2 decodedData, 解码数据,可通过getFrameSize获取长度 3 encodedData.length
编码参数1 audioData,原始参数
2 0
3 encodedData,
4 audioData.length