如何从无符号字符(8位)缓冲区读取短整数(16位)

How to read short (16bits) integers from an unsigned char (8bits) buffer

本文关键字:缓冲区 读取 短整数 16位 8位 无符号 字符      更新时间:2023-10-16

如标题所示,我需要从字符缓冲区中读取短整数

缓冲

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来实现这一点,但我没有成功地获得合理的值,所以我尝试使用联合结构,正如StackOverflow中的一些相关问题所建议的那样。我的代码如下:并集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将其写入设备时,我只会收到咔嗒声。我转换的方式不对吗?你能帮我找到一些更好的阅读方法吗?

非常感谢您的帮助

Alba

把uint8_t数组想象成一个原始字节数组。在C/C++中,unsigned char(uint8_t)尽可能接近于一个"无类型"数组。任何类型的数据都可以作为原始字节写入任何类型的数组,但与无符号字符数组交互最容易,因为每个元素都是0x00到0xFF(一个字节)之间的值,用户可以根据自己的选择来解释这些字节。

如果您只是将数据从ffmpeg传递到PortAudio,那么您可能不需要自己对数据进行任何解释。PortAudio的回调(如果使用阻塞API,则为写入方法)要求用户设置一个指向正在播放的数据缓冲区开头的空指针。缓冲区是什么类型并不重要,只要字节在按顺序读取时可以被解释为预期的样本格式即可。事实上,您甚至可能不需要复制数据,只要您能够将缓冲区指针传递给回调,并且缓冲区在被回调处理之前不会被释放。注意其他问题,如阅读单声道流和编写立体声流。如果您的输出流期望交错立体声音频,则必须将每个样本写入输出缓冲区两次(或者为期望的每个通道写入一次)。

另一方面,如果您希望操作缓冲区中的样本,您可能希望将uint8_t*重新解释为短*。由于缓冲区中的数据已经是有符号的16位样本,因此一旦进行强制转换,数组中的每个元素都将是一个数据样本。请记住,数组的大小只有原始缓冲区的一半,因为元素是原始缓冲区大小的两倍。

这应该是完全安全的,并且只要您在单个系统上工作,就不应该在ffmpeg和PortAudio之间移动样本时出现任何端序问题。如果系统是big-endian,则样本将是big-ndian(最低地址中的高位字节,Motorolla),如果系统是little-endian(最小地址中的低位字节,Intel),则样本将会是little-endian。

对我来说,这看起来是错误的:

     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个字节[每个样本的比特数,每秒的样本数],然后是输出中的样本数,以及之后的样本数)。