Android NDK Libspeex导致神秘的本机崩溃

时间:2018-05-04 01:07:08

标签: android-ndk

我想在我的Android应用程序中使用libspeex,所以我基本上将库从LineageOS 14.1 sources复制到项目中。然后我写了一个简单的jni:

#include <jni.h>
#include <android/log.h>
#include <include/speex/speex_bits.h>
#include <include/speex/speex.h>
#include <stdlib.h>
#include <string.h>

SpeexBits enc_bits, dec_bits;
void* enc_state = NULL;
void* dec_state = NULL;
int frame_size = 0;

JNIEXPORT jint JNICALL
Java_dt_test_Codec_encode(JNIEnv *env, jclass type, jshortArray input_, jbyteArray output_)
{
    if(enc_state == NULL)
    {
        return 0;
    }

    //check the input size is correct
    int input_size = (int)(*env)->GetArrayLength(env, input_);
    if(input_size != frame_size)
    {
        return 0;
    }

    //encode
    jshort* input = (*env)->GetShortArrayElements(env, input_, NULL);
    speex_bits_reset(&enc_bits);
    speex_encode_int(enc_state, input, &enc_bits);

    //write output
    int nbBytes = 0;
    char* output = (char*)malloc((size_t)frame_size); //output can't be bigger than the input
    memset(output, 0, (size_t)frame_size);
    nbBytes = speex_bits_write(&enc_bits, output, frame_size);
    (*env)->SetByteArrayRegion(env, output_, 0, nbBytes, (jbyte*)output);

    //cleanup
    free(output);
    (*env)->ReleaseShortArrayElements(env, input_, input, 0);
    return  nbBytes;
}

JNIEXPORT void JNICALL
Java_dt_test_Codec_closeEncoder(JNIEnv *env, jclass type)
{
    speex_bits_destroy(&enc_bits);
    speex_encoder_destroy(enc_state);
    enc_state = NULL;
    memset(&enc_bits, 0, sizeof(enc_bits));
    frame_size = 0;
}

JNIEXPORT jint JNICALL
Java_dt_test_Codec_getFramesize(JNIEnv *env, jclass type)
{
    return frame_size;
}

JNIEXPORT void JNICALL
Java_dt_test_Codec_decode(JNIEnv *env, jclass type, jbyteArray input_, jshortArray output_)
{
    if(dec_state == NULL)
    {
        return;
    }

    jbyte* input = (*env)->GetByteArrayElements(env, input_, NULL);
    int input_size = (int)(*env)->GetArrayLength(env, input_);
    speex_bits_read_from(&dec_bits, (char*)input, input_size);
    short* output = (short*)malloc((size_t)frame_size);
    speex_decode_int(dec_state, &dec_bits, output);
    (*env)->SetShortArrayRegion(env, output_, 0, frame_size, output);

    (*env)->ReleaseByteArrayElements(env, input_, input, 0);
    free(output);
}

JNIEXPORT void JNICALL
Java_dt_test_Codec_closeDecoder(JNIEnv *env, jclass type)
{
    speex_bits_destroy(&dec_bits);
    speex_decoder_destroy(dec_state);
    dec_state = NULL;
    memset(&dec_bits, 0, sizeof(dec_bits));
}

JNIEXPORT void JNICALL
Java_dt_test_Codec_initEncoder(JNIEnv *env, jclass type)
{
    //cleanup old stuff if necessary
    if(enc_state != NULL)
    {
        Java_dt_test_Codec_closeEncoder(env, NULL);
    }

    //setup encoder
    speex_bits_init(&enc_bits);
    enc_state = speex_encoder_init(&speex_uwb_mode);
    speex_encoder_ctl(enc_state, SPEEX_GET_FRAME_SIZE, &frame_size);
    int quality = 7;
    speex_encoder_ctl(enc_state, SPEEX_SET_QUALITY, &quality);
}

JNIEXPORT void JNICALL
Java_dt_test_Codec_initDecoder(JNIEnv *env, jclass type)
{
    //cleanup old stuff if necessary
    if(dec_state != NULL)
    {
        Java_dt_test_Codec_closeDecoder(env, NULL);
    }

    //setup decoder
    speex_bits_init(&dec_bits);
    dec_state = speex_decoder_init(&speex_uwb_mode);
}

我只是在未初始化的0数组上调用encode,并在无限循环中解码以下结果以查看jni的运行情况。但是,我似乎总是在渲染线程中发生本机崩溃,并在地址0x60处发生分段错误。地址始终相同,线程也是如此。堆栈跟踪只是一堆未知数。在进一步调查中,如果我只在循环中编码而不是解码,则不会发生这种崩溃。我已经按照说明如何使用speex编解码器完全来自:the speex website我无法想到编解码器如何在Android的渲染线程中导致崩溃的任何好的解释我甚至都没碰过那个区域。

Java部分:

                    Codec.initEncoder();
                    Codec.initDecoder();
                    WAVBUFFERSHORTS = Codec.getFramesize();

                    while (true)
                    {
                        short[] wavshorts = new short[WAVBUFFERSHORTS];


                        Codec.encode(wavshorts, encbuffer);
                        short[] reconstruct = new short[WAVBUFFERSHORTS];
                        Codec.decode(encbuffer, reconstruct);

0 个答案:

没有答案