发现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);
}