我正在尝试使用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的风险。
最佳答案
GetByteArrayRegion
检查数组的边界以确保没有超出末尾。GetByteArrayElements
只获取指向数组开头的指针,因此您的memcpy()
可以在未被注意的情况下自由地运行到结尾。
超限的原因在异常中说明:
[B offset=12 length=1634 src.length=1634
[B
表示byte[]
。数组的长度与请求的长度(1634)匹配,但它是从偏移量12字节开始进入数组的。所以你试着读12个字节。Java代码中抛出的异常不会中断C代码;VM只是在当前线程上设置一个标志。必须用“cc>”显式地测试它们,并清除它们或返回到Java代码,在那里VM将继续抛出进程。如果您启用了checkjni,并且vm看到您只进行了几个调用,但却引发了一个异常,那么您将得到一个“jni警告”和vm中止。
关于android - GetByteArrayRegion导致ArrayIndexOutOfBoundsException,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19881355/