在标题中我需要从char缓冲区中读取短整数
缓冲区
uint8_t *data[AV_NUM_DATA_POINTERS]
这是AVFrame frame
结构的一个字段,通过调用ffmpeg函数来填充
avcodec_decode_audio4(avctx,frame,got_frame_ptr,avpkt)
但是,我需要将此缓冲区作为带符号16位整数的缓冲区读取,因为这是编解码器上下文指示的样本格式 avctx-> sample_fmt == AV_SAMPLE_FMT_S16
我尝试使用memcpy这样做,但是我没有成功获得合理的值,所以我尝试使用一个union结构,如StackOverflow中的一些相关问题所示。我的代码如下: union CharToStruct { uint8_t myCharArray [2]; 短期价值; } presentSound;
audioRet=avcodec_decode_audio4(avctx,frame,got_frame_ptr,avpkt);
if(got_frame_ptr){
audioRet=audioRet/2;
int b=0;
for(int i=0;i<audioRet;i++){
presentSound.myCharArray[0]=frame->data[0][2*i+1];
presentSound.myCharArray[1]=frame->data[0][2*i]
dbuf[((i-b)/2)*8+info->mLeft+b]=info->presentSound.value;//the reason of the offset by 8 here is because I will be writing the result to a multichannel device
}
有了这个,这些值是合理的,但是当我使用portaudio将其写入设备时,我只是点击了噪音。我是以错误的方式进行转换吗?你能帮助我一些更好的方法来阅读吗?
非常感谢您的帮助
芭
答案 0 :(得分:0)
对我而言,这看起来不对:
presentSound.myCharArray[0]=frame->data[0][2*i+1];
presentSound.myCharArray[1]=frame->data[0][2*i]
我希望看到:
presentSound.myCharArray[0]=frame->data[0][2*i]
presentSound.myCharArray[1]=frame->data[0][2*i+1];
可能值得将数据写入文件,并附加WAV标头(从正确格式的现有文件中获取前40个字节[每个样本的位数,每秒样本数],然后是样本数输出,以及之后的样本。)
答案 1 :(得分:0)
只需将uint8_t数组视为原始字节数组。在C / C ++中,unsigned char(uint8_t)尽可能接近“无类型”数组。任何类型的数据都可以作为原始字节写入任何类型的数组,但最简单的方法是与unsigned char数组进行交互,因为每个元素的值都是0x00到0xFF(一个字节),用户可以解释这些字节然后选择
如果您只是将数据从ffmpeg传递到PortAudio,则可能不需要自己对数据进行任何解释。 PortAudio的回调(或写入方法,如果使用阻塞API)要求用户设置一个void指针指向正在播放的数据缓冲区的开头。无论缓冲区是什么类型,只要按顺序读取的字节可以解释为预期的样本格式。实际上,只要您能够将缓冲区指针传递给回调并且缓冲区在被回调处理之前不会被释放,您甚至可能不需要复制数据。注意其他问题,如读取单声道流和编写立体声流。如果您的输出流期望交错立体声音频,则必须将每个样本写入输出缓冲区两次(或者每个通道预期一次)。
另一方面,如果您希望操作缓冲区中的样本,您可能希望将uint8_t *重新解释为一个短*。由于缓冲区中的数据已经签名为16位样本,因此一旦进行转换,阵列中的每个元素都将成为一个数据样本。请记住,数组的大小只是原始缓冲区的一半,因为元素的大小是原来的两倍。
这应该是完全安全的,只要您在单个系统上工作,就不应该在ffmpeg和PortAudio之间移动样本时出现任何字节序问题。如果系统是大端,则样本将是大端(最低地址中的高位字节,Motorolla),如果系统是小端(最低地址中的低位字节,Intel),则样本将是小端。