【问题标题】:Collect decoded audio from libav as doubles从 libav 收集解码的音频作为双打
【发布时间】:2015-10-18 00:07:48
【问题描述】:

我目前正在尝试收集解码的音频数据(来自多种格式)以执行某些音频操作(使用 *.wav 文件进行测试)。

我有一个通过 FFmpeg libav 处理所有解码的类。如果我将数据作为 unit8_t 提取到向量中,并且

for (int i = 0; i < bytevector.size(); i++) {
    fwrite(&bytevector[i], sizeof (uint8_t), 1, outfile2);
}

到一个原始文件并通过它播放 play -t raw -r 44100 -b16 -c 1 -e signed sound.raw 听起来很好。

但是,当文件是每个样本 2 个字节并且frame-&gt;data 信息以 uint8_t 形式给出时,如何将所有 正确信息 加倍?我测试过的 wav 文件是 44100/16bits/1 通道。 (我已经有将 uint8_t* 更改为双精度的代码)

使用 Scilab 打开相同的文件将显示一半大小的字节向量作为双精度数。

Scilab 中的 wav 文件作为双精度数组显示:
-0.1, -0.099, -0.098, ..., 0.099, +0.1

与字节向量:
51, 243, 84, 243, 117, 243, ...

51和243真的可以组成一个double吗?有关如何解决此问题的任何建议?

以下代码供参考:

 while ((av_read_frame(formatContext, &readingPacket)) == 0) {
        if (readingPacket.stream_index == audioStreamIdx) {
            AVPacket decodingPacket = readingPacket;

            while (decodingPacket.size > 0) {
                int gotFrame = 0;
                int result = avcodec_decode_audio4(context, frame, &gotFrame, &decodingPacket);

                if (result < 0) {
                    break;
                }

                decoded = FFMIN(result, decodingPacket.size);

                if (gotFrame) {
                    data_size = (av_get_bytes_per_sample(context->sample_fmt));
                    if (data_size < 0) {
                    }

                    // Only for 1 channel temporarily
                    for (int i = 0; i < frame->nb_samples; i++) {
                        for (int ch = 0; ch < context->channels; ch++) {
                            for (int j = 0; j < data_size; j++) {
                                bytevector.push_back(*(frame->data[ch] + data_size * i + j)); 
                            }
                        }
                    }
                } else {
                    decodingPacket.size = 0;
                    decodingPacket.data = NULL;
                }
                decodingPacket.size -= result;
                decodingPacket.data += result;
            }
        }
        av_free_packet(&readingPacket);
    }

【问题讨论】:

  • double ?这可能是 52 位精度、11 位动态范围或 6000 dB。那太疯狂了。而命令行中的-b16 表示 16 位,不是 8 位。
  • Double 对于对音频所做的事情来说绝对是矫枉过正。当在查看器中打开数组时,Scilab 将值显示为“双精度值”,这让我感到震惊。但是,是的,下面是关于如何以与 Scilab 相同的方式(范围从 -1.0 到 +1.0)表示两个 uint8_t(或 2 个字节)的数据的答案。谢谢。
  • @MSalters - 大多数体面的 DAW 应用程序使用 64 位内部处理,这样即使您仍然输出 24 位母版,您也会损失更少的精度。
  • @ddriver:那可能是 64 位 PCM。动态范围为 190 dB,而不是 6000。相比之下,广岛约为 250 dB。一颗正在形成超新星的恒星不超过 1000 分贝。

标签: c++ audio ffmpeg decode libav


【解决方案1】:

两个字节转换为浮点数的快速方法:

byte bits[] = {195,255}; //first sample in the test s16 wav file
int16_t sample;
memcpy(&sample,&bits,sizeof(bits));
std::cout<<sample*(1.0f/32768.0f)<<std::endl;

此代码在打印时产生-0.001861572265625(使用更精确的 setprecision(xx);),这是 Scilab 使用相同文件给出的第一个数字。

我希望这可以帮助任何有类似问题的人。

【讨论】:

    【解决方案2】:

    音频数据以多种不同格式存储。你得到一个uint8_t[] 数组意味着相当少。每个数组不是一个字节。相反,您需要知道格式。这里-b16 告诉我uint8_t[] 数据实际上是 16 位 PCM 编码数据,即范围从 -32768 到 +32767。 Scilab 似乎更喜欢浮点刻度,因此除以 32768.0。这只是表示形式的变化;它只是将比例缩小到 -1.0、+1.0。

    将其与角度进行比较:直角在 pi/2 弧度上是 90 度;确切的数字无关紧要,但都是整圈的 1/4。

    【讨论】:

      猜你喜欢
      • 2014-04-23
      • 1970-01-01
      • 2013-12-24
      • 2020-10-13
      • 1970-01-01
      • 1970-01-01
      • 2014-02-06
      • 2012-11-30
      • 2015-05-21
      相关资源
      最近更新 更多