3

Speex ライブラリを使用して Speex でエンコードされたオーディオ ファイルをデコードしようとしていますが、常にArrayIndexOutOfBoundsException

JNIEXPORT jint JNICALL Java_com_app_shared_Speex_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;

        env->GetByteArrayRegion(encoded, rtp_header, encoded_length, buffer);

        /*  
        jboolean isCopy;
        jbyte* data = env->GetByteArrayElements(encoded, &isCopy);
        if(isCopy){
        memcpy(buffer, data, encoded_length);               
        env->ReleaseByteArrayElements(encoded, data, JNI_ABORT);
        }
        */

        speex_bits_read_from(&dbits, (char *)buffer, encoded_length);
        speex_decode_int(dec_state, &dbits, output_buffer);

        std::string bufStr;

        for(int i=0; i<20; i++){
            char buff[100];
            sprintf(buff, "Speex test %d => %d", i, output_buffer[i]);
            bufStr = buff;
            LOGI(bufStr.c_str());
        }

        bufStr = "before SetShortArrayRegion";
        LOGI(bufStr.c_str());

        (env)->SetShortArrayRegion(lin, rtp_header, dec_frame_size, output_buffer);

        bufStr = "after SetShortArrayRegion";
        LOGI(bufStr.c_str());

        return (jint)dec_frame_size;            
}

私は得る:

SharedSpeex before SetShortArrayRegion
dalvikvm    JNI WARNING: JNI method called with exception pending
dalvikvm              in Lcom/company/shared/Speex;.decode:([B[SI)I (SetShortArrayRegion)
dalvikvm    Pending exception is:
dalvikvm    java.lang.ArrayIndexOutOfBoundsException: [B offset=12 length=1634 src.length=1634

興味深い点は、 を含む行を完全にコメントするとSetShortArrayRegion、スコープを終了するときに例外が発生することです。

SharedSpeex       before SetShortArrayRegion
SharedSpeex       after SetShortArrayRegion
AndroidRuntime    Shutting down VM
dalvikvm          threadid=1: thread exiting with uncaught exception (group=0xa62ca288)
AndroidRuntime    FATAL EXCEPTION: main
AndroidRuntime    java.lang.ArrayIndexOutOfBoundsException: [B offset=12 length=1634 src.length=1634

公式のJNIドキュメントでは、次の理由により、明らかに優先さGetByteArrayRegionれます。GetByteArrayElements

  • プログラマー エラーのリスクを軽減します — 何かが失敗した後に Release を呼び出すのを忘れるリスクはありません。
4

1 に答える 1

5

GetByteArrayRegion配列の境界をチェックして、最後まで実行していないことを確認します。 GetByteArrayElements配列の先頭へのポインターを取得するだけなので、memcpy()気づかれずに末尾を越えて自由に実行できます。

オーバーランの理由は、例外に記載されています。

[B offset=12 length=1634 src.length=1634

[Bを意味しbyte[]ます。配列の長さはリクエストの長さ (1634) と一致しますが、配列への 12 バイトのオフセットから始まっています。したがって、最後から 12 バイトを読み取ろうとしています。

Java コードからスローされた例外は、C コードを中断しません。VM は現在のスレッドにフラグを設定するだけです。を使用して明示的にテストし、それらをExceptionCheckクリアするか、VM がスロー プロセスを続行する Java コードに戻る必要があります。CheckJNI を有効にしていて、例外が発生したほんの一握りの呼び出しを VM が検出すると、「JNI 警告」が表示され、VM が中止されます。

于 2013-11-10T17:35:06.490 に答える