【问题标题】:Struct C/C++ - Reading WAV Header 32 Bit Float - byte offset wrong结构 C/C++ - 读取 WAV 标头 32 位浮点数 - 字节偏移错误
【发布时间】:2017-06-04 15:44:00
【问题描述】:

我使用一个结构来读取音频格式 3(=IEEE FLOAT 32 位)和 58 字节 wav 头的 Wav 文件。问题:字节 38 以“事实”块开头。这似乎没问题。 DwFactSize 的偏移量应该是 42。问题就从这里开始!偏移量是 44 !!!首先我想,问题出在填充位上。所以我尝试了 uint、无符号字符和 attribute((packed))。这不会改变任何事情。

这是wav头的定义:

0 - 3 'RIFF'/'RIFX' 小/大端

4 - 7 wRiffLength 文件长度减去 8 字节 riff 标头

8 - 11 '波'

12 - 15 'fmt'

16 - 19 wFmtSize 格式块长度减去 8 字节头

20 - 21 wFormatTag 标识 PCM、ULAW 等

22 - 23 个 wChannels

每个通道每秒 24 - 27 个 dwSamplesPerSecond 样本

28 - 31 dwAvgBytesPerSec 对于压缩格式来说非常重要

32 - 33 wBlockAlign 基本块大小

34 - 35 wBitsPerSample 对压缩格式很重要

(直到第 35 个字节,就像通常的 44 字节标头一样)

36 - 37 wExtSize = 0 格式扩展的长度

38 - 41 '事实'

42 - 45 dwFactSize = 4 事实块的长度减去 8 字节 标题

46 - 49 dwSamplesWritten 实际写出的样本数

50 - 53 '数据'

54 - 57 dwDataLength 数据块长度减去 8 字节头


输出:

...

直到这里......正确......

事实[4] 38

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

DwFactSize 44

dwSamplesWritten 48

数据[4] 52

dwDataLength 56

快速破解显示偏移问题:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <cstring>
#include <iostream>
#include <cstddef>

typedef struct  WAV_HEADER
{
unsigned char       RIFF[4];        /* RIFF Header      */ //Magic header
unsigned long       ChunkSize;      /* RIFF Chunk Size  */
unsigned char       WAVE[4];        /* WAVE Header      */
unsigned char       fmt[4];         /* FMT header       */
unsigned long       Subchunk1Size;  /* Size of the fmt chunk: 16=PCM, 18=IEEE Float, 40=Extensible                     */
unsigned short      AudioFormat;    /* Audio format 1=PCM, 3=IEEE Float, 6=mulaw,7=alaw, 257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM, 65534=Extensible */
unsigned short      NumOfChan;      /* Number of channels 1=Mono 2=Stereo                   */
unsigned long       SamplesPerSec;  /* Sampling Frequency in Hz                             */
unsigned long       bytesPerSec;    /* bytes per second */
unsigned short      blockAlign;     /* 2=16-bit mono, 4=16-bit stereo , 6=24-bit stereo,8=32-bit stereo*/
unsigned short      bitsPerSample;  /* Number of bits per sample, inkl. hier=36 bytes  */
unsigned short      wExtSize;       /*  2 byte, wExtSize = 0  the length of the format extension   */
unsigned char       Fact[4];        /* "fact"  string   */
/*Problem here! -> +2bytes*/
unsigned long       DwFactSize;     /* Sampled data length,  inkl. hier bei 44 bytes */
unsigned long       dwSamplesWritten;
unsigned char       Data[4];        /* leerer string falls extensible -> Beginn nicht nach 44 sondern 68!  */
unsigned long       dwDataLength;   /* raw DataLength */
}__attribute__((packed)) wav_hdr;


int getFileSize(FILE *inFile);

int main(int argc,char *argv[])
{
char *file;
file = argv[1];
wav_hdr wavHeader;
FILE *wavFile;
int headerSize = sizeof(wav_hdr),filelength = 0;
wavFile = fopen(file,"r");
if(wavFile == NULL)
{
    printf("\nCan not open wave file. Usage: program [file] \n");
    exit(EXIT_FAILURE);
}

fread(&wavHeader,headerSize,1,wavFile);
filelength = getFileSize(wavFile);
fclose(wavFile);


std::cout << "\nRIFF " << offsetof(WAV_HEADER, RIFF) <<  std::endl;
std::cout << "\nChunkSize " << offsetof(WAV_HEADER, ChunkSize) <<  std::endl;
std::cout << "\nWAVE[4] " << offsetof(WAV_HEADER, WAVE) <<  std::endl;
std::cout << "\nfmt[4] " << offsetof(WAV_HEADER, fmt) <<  std::endl;
std::cout << "\nSubchunk1Size " << offsetof(WAV_HEADER, Subchunk1Size) <<  std::endl;
std::cout << "\nAudioFormat " << offsetof(WAV_HEADER, AudioFormat) <<  std::endl;
std::cout << "\nNumOfChan " << offsetof(WAV_HEADER, NumOfChan) <<  std::endl;
std::cout << "\nSamplesPerSec " << offsetof(WAV_HEADER, SamplesPerSec) <<  std::endl;
std::cout << "\nbytesPerSec " << offsetof(WAV_HEADER, bytesPerSec) <<  std::endl;
std::cout << "\nblockAlign " << offsetof(WAV_HEADER, blockAlign) <<  std::endl;
std::cout << "\nbitsPerSample " << offsetof(WAV_HEADER, bitsPerSample) <<  std::endl;
std::cout << "\nwExtSize (2) " << offsetof(WAV_HEADER, wExtSize) <<  std::endl;
std::cout << "\nFact[4] " << offsetof(WAV_HEADER, Fact) <<  std::endl;

std::cout << "\nDwFactSize " << offsetof(WAV_HEADER, DwFactSize) <<  std::endl;
std::cout << "\ndwSamplesWritten " << offsetof(WAV_HEADER, dwSamplesWritten) <<  std::endl;
std::cout << "\nData[4] " << offsetof(WAV_HEADER, Data) <<  std::endl;
std::cout << "\ndwDataLength " << offsetof(WAV_HEADER, dwDataLength) <<  std::endl;


return 0;
}

int getFileSize(FILE *inFile)
{
int fileSize = 0;
fseek(inFile,0,SEEK_END);
fileSize=ftell(inFile);
fseek(inFile,0,SEEK_SET);
return fileSize;
}

要生成这样一个 32 位浮点、88200 Wav 文件: sox input16_44100.wav -b 32 -e float output32F_88200.wav rate -s -a -v -L 88200

【问题讨论】:

  • 离题的话题(如果是在话题上,你的偏移量会很远)你绝对确定shortlong的大小吗?使用fixed-width integers 可能会更好
  • 热门话题,如果您逐个阅读字段而不是指望结构的包装与作者的匹配,会发生什么?
  • 就像我写的那样,我使用了 unsigned char、uint16_t、uint32_t ... 在事实块之后也是如此。这适用于 44 字节标头多年...
  • @TJF 这个问题是为了求职而提出的吗?
  • PEAK 头呢?

标签: c++ wav


【解决方案1】:

Fact[]DwFactSize 之间显然有 2 个字节的填充。

我怀疑这是因为您在那里使用了typedef。只需将其编写为常规 C++ 定义:struct __attribute__((packed)) WAV_HEADER { ...

【讨论】:

  • 是的,这 2 个字节是问题所在。我试过你的建议......但没有成功......
  • 当我这样做时,标题大小是正确的:unsigned char DwFactSize[4];无符号字符 dwSamplesWritten[4];无符号字符数据[4];无符号字符 dwDataLength[4];但原因是什么?这将几乎无法使用...
  • @TJF:插入填充以强制对齐限制,但char 没有对齐限制。我推荐uint32_t DataLength() const - 一个函数,而不是数据成员。
  • 您能否再解释一下,或者您有什么例子...?
  • @TJF:见existing questions - 那里已经有很多很好的信息了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-08
  • 1970-01-01
  • 2010-09-05
  • 1970-01-01
  • 1970-01-01
  • 2011-04-28
相关资源
最近更新 更多