简体   繁体   English

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

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

As in the title I need to read short integers from a char buffer 如标题中所示,我需要从char缓冲区读取短整数

The buffer 缓冲区

uint8_t *data[AV_NUM_DATA_POINTERS]

which is a field of the AVFrame frame structure, is filled by a call to the ffmpeg function 它是AVFrame frame结构的一个字段,由对ffmpeg函数的调用填充

avcodec_decode_audio4(avctx,frame,got_frame_ptr,avpkt)

But, I need to read this buffer as a buffer of signed 16 bits integers because this is the sample format indicated by the codec context avctx->sample_fmt==AV_SAMPLE_FMT_S16 但是,我需要将此缓冲区读取为带符号的16位整数的缓冲区,因为这是编解码器上下文avctx-> sample_fmt == AV_SAMPLE_FMT_S16指示的示例格式

I tried to do this using a memcpy but I have not succeeded to get reasonable values so then I tried to use a union struct as suggested on some related questions here in StackOverflow. 我尝试使用memcpy来执行此操作,但是我没有成功获取合理的值,因此我尝试按照StackOverflow中一些相关问题的建议使用联合结构。 My code is as follows: union CharToStruct{ uint8_t myCharArray[2]; 我的代码如下:union CharToStruct {uint8_t myCharArray [2]; short value; 短价值 } presentSound; } 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
 }

With this, the values are reasonable, but when I write this to a device using portaudio, I get just clicking noise. 这样,这些值是合理的,但是当我使用portaudio将其写入设备时,我只会听到咔嗒声。 Am I doing the conversion in a wrong way? 我是否以错误的方式进行转换? Can you help me maybe with some better way to do this reading? 您能否以某种更好的方式帮助我阅读本书?

Thank you very much for your help 非常感谢您的帮助

Alba 阿尔巴

To me, this looks wrong: 对我来说,这看起来是错误的:

     presentSound.myCharArray[0]=frame->data[0][2*i+1];
     presentSound.myCharArray[1]=frame->data[0][2*i]

I would expect to see: 我希望看到:

     presentSound.myCharArray[0]=frame->data[0][2*i]
     presentSound.myCharArray[1]=frame->data[0][2*i+1];

It may be worth writing the data out to a file, and append a WAV header (take the first 40 bytes from an existing file of the right format [bits per sample, samples per second], then the number of samples in the output, and the samples after that). 可能值得将数据写到文件中,并附加一个WAV标头(从正确格式的现有文件中提取前40个字节[每个样本的位数,每秒的样本数],然后在输出中获取样本数,以及之后的样本)。

Just think of a uint8_t array as a raw byte array. 只需将uint8_t数组视为原始字节数组即可。 In C/C++ unsigned char (uint8_t) is as close to a "typeless" array as you can get. 在C / C ++中,无符号字符(uint8_t)尽可能接近“无类型”数组。 Any type of data can be written to any type array as raw bytes, but it is easiest to interact with an unsigned char array because each element is a value from 0x00 to 0xFF (one byte) and the user can interpret those bytes however they choose. 任何类型的数据都可以作为原始字节写入任何类型的数组,但是与无符号char数组进行交互最容易,因为每个元素都是0x00到0xFF(一个字节)之间的值,并且用户可以解释这些字节,但是他们选择。

You may not need to do any interpretation of the data on your own, if you are simply passing the data from ffmpeg to PortAudio. 如果您只是将数据从ffmpeg传递到PortAudio,则可能不需要自己对数据进行任何解释。 PortAudio's callback (or write method if using the blocking API) requires that the user set a void pointer to the beginning of the data buffer being played. PortAudio的回调(或使用阻塞API的写方法)要求用户将空指针设置为正在播放的数据缓冲区的开头。 It does not matter what type that buffer is, as long as the bytes, when read in order, can be interpreted as the expected sample format. 缓冲区的类型无关紧要,只要按顺序读取字节,就可以将其解释为预期的样本格式。 In fact you may not even need to copy the data as long as you are able to pass the buffer pointer to the callback and the buffer doesn't get deallocated before being processed by the callback. 实际上,只要您能够将缓冲区指针传递给回调并且缓冲区在被回调处理之前不会被释放,您甚至甚至不需要复制数据。 Watch out for other issues like reading a mono stream and writing a stereo stream. 注意其他问题,例如阅读单声道流和编写立体声流。 If you're output stream is expecting interleaved stereo audio, you'll have to write each sample to the output buffer twice (or once for each channel it is expecting). 如果输出流期望交织的立体声音频,则必须将每个样本两次写入输出缓冲区(或对于期望的每个通道一次)。

On the other hand if you wish to manipulate the samples in the buffer, you may wish to reinterpret_cast the uint8_t* to a short*. 另一方面,如果您希望操作缓冲区中的样本,则可能希望将uint8_t *重新解释为short *。 Since the data in the buffer is already signed 16-bit samples, once you cast, each element in the array will be one sample of data. 由于缓冲区中的数据已经是带符号的16位样本,因此一旦进行转换,数组中的每个元素将是一个数据样本。 Just remember that the size of the array will only be half that of the original buffer since the elements are twice as big. 请记住,由于元素的大小是数组的两倍,因此数组的大小将仅为原始缓冲区的一半。

This should be entirely safe and you should not have any endianness issues moving samples between ffmpeg and PortAudio as long as you are working on a single system. 这应该是完全安全的,并且只要在单个系统上工作,在ffmpeg和PortAudio之间移动样本就不会有任何字节序问题。 If the system is big endian the samples will be big endian (high order byte in the lowest address, Motorolla), if the system is little endian (low order byte in lowest address, Intel) the samples will be little endian. 如果系统是大字节序,则样本将是大字节序(最低地址中的高位字节,Motorolla),如果系统是小字节序(在最低地址中低序字节,Intel),则样品将是小字节序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM