【问题标题】:How to read short (16bits) integers from an unsigned char (8bits) buffer如何从无符号字符(8 位)缓冲区中读取短(16 位)整数
【发布时间】:2013-08-25 20:49:15
【问题描述】:

如标题所示,我需要从 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 来执行此操作,但我没有成功获得合理的值,因此我尝试按照 StackOverflow 中一些相关问题的建议使用联合结构。我的代码如下: 联合 CharToStruct{ uint8_t myCharArray[2]; 短期价值; } 呈现声音;

 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 将它写入设备时,我只会听到咔嗒声。我是否以错误的方式进行转换?你能帮我用一些更好的方法来做这个阅读吗?

非常感谢您的帮助

阿尔巴

【问题讨论】:

    标签: c++ casting ffmpeg short portaudio


    【解决方案1】:

    只需将 uint8_t 数组视为原始字节数组。在 C/C++ 中,unsigned char (uint8_t) 尽可能接近“无类型”数组。任何类型的数据都可以作为原始字节写入任何类型的数组,但与 unsigned char 数组交互是最容易的,因为每个元素都是一个从 0x00 到 0xFF(一个字节)的值,用户可以根据自己的选择解释这些字节.

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

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

    这应该是完全安全的,只要您在单个系统上工作,在 ffmpeg 和 PortAudio 之间移动样本就不会有任何字节顺序问题。如果系统是大端,则样本将是大端(最低地址中的高位字节,摩托罗拉),如果系统是小端(最低地址中的低位字节,英特尔),则样本将是小端。

    【讨论】:

      【解决方案2】:

      在我看来,这看起来不对:

           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 个字节 [bits per sample, samples per second],然后是输出,以及之后的样本)。

      【讨论】:

      • 哦,谢谢,将结果写入 wav 文件是个好主意,这样我可以查看播放时的声音是否符合预期。
      • 这个对相关问题link 的回答建议将第二个字节放在第一位,告诉短片中的最高有效位是最后一个。但我也尝试了另一种方式,先是 [2*i] 然后是 [2*i+1] 和我得到的数字太小以至于我什么都听不见。
      猜你喜欢
      • 1970-01-01
      • 2015-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多