You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JNI中从C char数组创建jshortArray的正确性及编解码交互疑问

问题1:char数组转jshortArray的代码正确性及内容一致性

你提供的代码存在内存越界和内容逻辑错误,生成的jshortArray不会和原char数组内容一致:

  • 内存越界问题:NewShortArray(s*2)创建了包含s*2个short元素的数组,总占用字节数是4*s(每个short占2字节),但你分配的char数组只有s字节。调用SetShortArrayRegion时会从b指针读取s*2*2=4s字节,远超内存分配范围,会触发未定义行为(比如崩溃、垃圾数据)。
  • 内容不一致问题:将char*强制转换为short const*后,系统会按当前字节序(大端/小端)把连续两个char字节拼接成一个short。比如原char数组是[0x01, 0x02, 0x03, 0x04],小端系统下会被解析为[0x0201, 0x0403],完全不是原char数组的内容。

如果需要把char数组的每个字节单独转为short(比如8位转16位),正确做法是创建长度为s的jshortArray,循环将每个char值赋值给对应的short元素;如果原char数组是16位PCM的字节流,应该创建长度为s/2的jshortArray,并按正确字节序拼接两个char为一个short。

问题2:libspx解码输出jshortArray的尺寸设置

基于libspx(speex)的解码逻辑,输出jshortArray的尺寸需要匹配解码后的PCM样本数,而非输入字节数的固定倍数:

  1. 首先通过libspx的API获取单帧样本数:调用speex_decoder_ctl(decoder, SPEEX_GET_FRAME_SIZE, &frame_size),其中frame_size就是每帧解码后输出的short样本数(窄带默认160,宽带默认320)。
  2. 根据输入压缩数据的总帧数,计算总样本数total_samples = frame_count * frame_size,以此作为jshortArray的长度。
  3. 注意:如果输入包含多帧,需要确保输出数组长度足够容纳所有解码样本;若Java层预先分配数组,需让其长度不小于计算出的total_samples,避免截断。
问题3:Java值传递与JNI数组操作的机制

Java数组的传递逻辑

Java确实是按值传递,但数组是对象,传递的是对象引用的副本。也就是说,native方法拿到的是Java数组对象的引用副本,指向的还是堆上同一个数组实例。因此你在native层修改数组内容后,Java层可以直接获取到修改后的结果。

JNI与C/C++数组操作的差异

  • C/C++中直接通过指针操作内存,数组本质是连续内存块的指针,传递指针就能直接修改原数组内容。
  • JNI中不能直接用指针操作Java数组(因为Java有垃圾回收,可能会移动数组内存),必须通过JNIEnv提供的安全函数:
    • 读取输入byte[]:用GetByteArrayElements获取数组的内存指针,使用完后调用ReleaseByteArrayElements释放。
    • 写入输出short[]:可以用SetShortArrayRegion直接写入指定区域,或者用GetShortArrayElements获取可修改的指针,写入后调用ReleaseShortArrayElements同步到Java堆。

针对你的native方法nDecodeBuffer的说明

你传入的short[] sArr是Java预先分配的数组,只要其长度足够容纳解码结果,在native层通过JNI函数写入数据后,Java层就能直接访问填充好的内容,不需要额外返回操作。

内容的提问来源于stack exchange,提问作者dev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 22:35:18