Opus解码输出全零问题求助:修改官方示例后异常
核心问题:错误的PCM数据转换逻辑
原官方示例里的in[i]=pcmdata[2*i+1]<<8|pcmdata[2*i];是用来把**磁盘读取的小端字节流(char类型)**转为主机字节序的opus_int16样本。但你直接生成的是opus_int16类型的PCM数组,却依然套用这个转换逻辑,导致原始音频数据被错误篡改,编码器最终编码的是无效/静音数据,解码自然输出全零。
具体修复步骤
移除错误的字节序转换
将填充in数组的代码从:for (i=0;i<CHANNELS*FRAME_SIZE;i++) in[i]=pcmdata[2*i+1]<<8|pcmdata[2*i];修改为直接赋值:
for (i=0;i<CHANNELS*FRAME_SIZE;i++) in[i] = pcmdata[i];因为
pcmdata本身就是opus_int16类型的PCM样本,不需要再做字节拼接。移除不必要的解码器重置
每次解码前调用opus_decoder_ctl(decoder, OPUS_RESET_STATE);会重置解码器状态,破坏解码上下文,导致无法正确处理编码后的数据包。直接删除这一行即可。初始化随机数种子(可选但推荐)
在随机数生成前添加srand(time(NULL));,确保每次运行生成不同的噪声数据,避免固定模式的音频输出。修正数组循环边界(可选)
你的循环for(short i=0;i<6553;i++)可以改为只生成当前一帧所需的数据量,比如for(int i=0;i<CHANNELS*FRAME_SIZE;i++),减少不必要的内存占用,也避免后续修改时出现越界风险。
修复后的核心代码片段
// 初始化随机数种子 srand(time(NULL)); ////////////////////////////////////////////////////////////////////// create audio noise #define RandZeroToOne ((float)rand() / RAND_MAX) #define RandNegOneToOne (((float)rand() / RAND_MAX)*2.0-1.0) opus_int16* pcmdata = (opus_int16*)calloc(65536, sizeof(opus_int16)); opus_int16* pDstData = (opus_int16*)calloc(65536, sizeof(opus_int16)); for(int i=0;i<CHANNELS*FRAME_SIZE;i++) { pcmdata[i] = (opus_int16)(RandZeroToOne*32767.0); if((i&0x1)==0) pcmdata[i] = -pcmdata[i]; } ////////////////////////////////////////////////////////////////////// //while (1) { int i; int frame_size; // 直接赋值PCM样本,无需字节转换 for (i=0;i<CHANNELS*FRAME_SIZE;i++) in[i] = pcmdata[i]; /* Encode the frame. */ nbBytes = opus_encode(encoder, in, FRAME_SIZE, cbits, MAX_PACKET_SIZE); if (nbBytes<0) { fprintf(stderr, "encode failed: %s\n", opus_strerror(nbBytes)); return EXIT_FAILURE; } /* Decode the data. */ frame_size = opus_decode(decoder, cbits, nbBytes, out, MAX_FRAME_SIZE, 0); if (frame_size<0) { fprintf(stderr, "decoder failed: %s\n", opus_strerror(frame_size)); return EXIT_FAILURE; } // 后续代码保持不变 }
额外说明
你的开发环境(VS2019、Windows SDK10、Win7 x64)完全符合Opus的运行要求,不需要特殊配置。问题完全源于代码逻辑错误,而非系统环境。测试时可以将解码后的out数组写入WAV文件,直接播放验证结果是否正常。
内容的提问来源于stack exchange,提问作者Archon 808

