webrtc中的wav文件格式解析

发现wav文件的格式解析有点小问题,原因就是不同的软件录制的wav文件里面有一些多余的头,这样就无法保证头的大小为44字节了,所以解析的代码需要注意这一点。我发现早前版本的webrtc里的源码就没有考虑到这一点,在解析ffmpeg转换后的wav文件和苹果录制的wav文件时,就出了问题。请看源码:webrtc/src/common_audio/wav_header.cc文件里的函数ReadWavHeader实现。

本人改写如下:

bool ReadWavHeader(ReadableWav* readable,
                   int* num_channels,
                   int* sample_rate,
                   WavFormat* format,
                   size_t* bytes_per_sample,
                   size_t* num_samples) {

    WavHeader header;
#if 0
    if (readable->Read(&header, kWavHeaderSize - sizeof(header.data)) !=
        kWavHeaderSize - sizeof(header.data))
        return false;

    const uint32_t fmt_size = ReadLE32(header.fmt.header.Size);
    if (fmt_size != kFmtSubchunkSize) {
        // There is an optional two-byte extension field permitted to be present
        // with PCM, but which must be zero.
        int16_t ext_size;
        if (kFmtSubchunkSize + sizeof(ext_size) != fmt_size)
            return false;
        if (readable->Read(&ext_size, sizeof(ext_size)) != sizeof(ext_size))
            return false;
        if (ext_size != 0)
            return false;
    }

    if (readable->Read(&header.data, sizeof(header.data)) != sizeof(header.data))
        return false;
#else
    while (true) {
        ChunkHeader unknown_header;
        if (readable->Read(&unknown_header, sizeof(unknown_header)) != sizeof(unknown_header))
            return false;

        std::string fourccID = ReadFourCC(unknown_header.ID);
        if (fourccID == "RIFF")
        {
            header.riff.header = unknown_header;
            if (readable->Read(&header.riff.Format, sizeof(header.riff.Format)) != sizeof(header.riff.Format))
                return false;
        }
        else if (fourccID == "fmt ")
        {
            header.fmt.header = unknown_header;
            if (readable->Read(&header.fmt.info, sizeof(header.fmt.info)) != sizeof(header.fmt.info))
                return false;

            const uint32_t fmt_size = ReadLE32(header.fmt.header.Size);
            if (fmt_size != kFmtSubchunkSize) {
                // There is an optional two-byte extension field permitted to be present
                // with PCM, but which must be zero.
                int16_t ext_size;
                if (kFmtSubchunkSize + sizeof(ext_size) != fmt_size)
                    return false;
                if (readable->Read(&ext_size, sizeof(ext_size)) != sizeof(ext_size))
                    return false;
                if (ext_size != 0)
                    return false;
            }
        }
        else if (fourccID == "data")
        {
            header.data.header = unknown_header;
            break;//until find data
        }
        else// if (fourccID == "LIST")//skip junk/list/fllr if exists
        {
            const size_t bytes_in_payload = ReadLE32(unknown_header.Size);
            if (readable->Seek(bytes_in_payload, SEEK_CUR) != 0)
                return false;
        }
    }
#endif
  // Parse needed fields.
  *format = static_cast<WavFormat>(ReadLE16(header.fmt.AudioFormat));
  *num_channels = ReadLE16(header.fmt.NumChannels);
  *sample_rate = ReadLE32(header.fmt.SampleRate);
  *bytes_per_sample = ReadLE16(header.fmt.BitsPerSample) / 8;
  const size_t bytes_in_payload = ReadLE32(header.data.header.Size);
  if (*bytes_per_sample == 0)
    return false;
  *num_samples = bytes_in_payload / *bytes_per_sample;

  // Sanity check remaining fields.
  if (ReadFourCC(header.riff.header.ID) != "RIFF")
    return false;
  if (ReadFourCC(header.riff.Format) != "WAVE")
    return false;
  if (ReadFourCC(header.fmt.header.ID) != "fmt ")
    return false;
  if (ReadFourCC(header.data.header.ID) != "data")
    return false;

  if (ReadLE32(header.riff.header.Size) < RiffChunkSize(bytes_in_payload))
    return false;
  if (ReadLE32(header.fmt.ByteRate) !=
      ByteRate(*num_channels, *sample_rate, *bytes_per_sample))
    return false;
  if (ReadLE16(header.fmt.BlockAlign) !=
      BlockAlign(*num_channels, *bytes_per_sample))
    return false;

  return CheckWavParameters(*num_channels, *sample_rate, *format,
                            *bytes_per_sample, *num_samples);
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值