Android NDK Libspeex вызывает таинственный сбой - PullRequest
0 голосов
/ 04 мая 2018

Я хочу использовать libspeex в своем приложении для Android, поэтому я по сути скопировал библиотеку в проект из источников LineageOS 14.1 . Затем я написал простой 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 с и декодирую следующий результат в бесконечном цикле, чтобы увидеть jni в действии. Тем не менее я, кажется, всегда получаю собственный сбой в потоке рендеринга с ошибкой сегментации по адресу 0x60. Адрес всегда один и тот же, как и поток. Трассировка стека - это просто стэк неизвестных. При дальнейшем расследовании этого сбоя не произойдет, если я только кодирую в цикле, а не декодирую. Я следовал инструкциям о том, как использовать кодек speex точно из: веб-сайта speex Я не могу придумать никакого хорошего объяснения того, как кодек вызывает сбой в потоке рендеринга 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...