RIFF和WAVE音頻文件格式

RIFF file format

RIFF全稱爲資源互換文件格式(Resources Interchange File Format),是Windows下大部分多媒體文件遵循的一種文件結構。RIFF文件所包含的數據類型由該文件的擴展名來標識,能以RIFF格式存儲的數據有:
- 音頻視頻交錯格式數據 .AVI
- 波形格式數據 .WAV
- 位圖數據格式 .RDI
- MIDI格式數據 .RMI
- 調色板格式 .PAL
- 多媒體電影 .RMN
- 動畫光標 .ANI
- 其他的RIFF文件 .BND

CHUNK

chunk是RIFF文件的基本單元,其基本結構如下:

struct chunk
{
    uint32_t id;   // 塊標誌
    uint32_t size; // 塊大小
    uint8_t data[size]; // 塊數據
};
  • id 4字節,用以標識塊中所包含的數據。如:RIFF,LIST,fmt,data,WAV,AVI等,由於這種文件結構 最初是由Microsoft和IBM爲PC機所定義,RIFF文件是按照小端 little-endian字節順序寫入的。
  • size 塊大小 存儲在data域中的數據長度,不包含id和size的大小
  • data 包含數據,數據以字爲單位存放,如果數據長度爲奇數(字節爲單位),則最後添加一個空字節。

chunk是可以嵌套的,但是隻有塊標誌爲RIFF或者LIST的chunk才能包含其他的chunk。

RIFF chunk

標誌爲RIFF的chunk是比較特殊的,每一個RIFF文件首先存放的必須是一個RIFF chunk,並且只能有這一個標誌爲RIFF的chunk。RIFF的數據域的起始位置是一個4字節碼(FOURCC),用於標識其數據域中chunk的數據類型;緊接着數據域的內容則是包含的subchunk,如下圖
這裏寫圖片描述
這是一個RIFF chunk中包含有兩個subchunk,可以看出RIFF chunk的數據域首先是是4字節的 Form Type,接着是兩個subchunk,每一個subchun有包含有自己的標識、數據域的大小以及數據域。
除了RIFF cunk可以嵌套其他的chunk外,另一個可以有subchunk的就是LIST chunk
這裏寫圖片描述
上圖中,首先是RIFF文件必須的RIFF chunk,其數據域又包含有兩個subchunk,其中一個subchunk的類型爲LIST,該LIST chunk又包含了兩個subchunk。

FourCC

FourCC 全稱爲Four-Character Codes,是一個4字節32位的標識符,通常用來標識文件的數據格式。例如,在音視頻播放器中,可以通過 文件的FourCC來決定調用那種CODEC進行視音頻的解碼。例如:DIV3,DIV4,DIVX,H264等,對於音頻則有:WAV,MP3等。對於上面的RIFF文件,則有:RIFF,WAVE,fmt,data等。FourCC是4個ASCII字符,不足四個字符的則在最後補充空格(不是空字符)。比如,FourCC fmt,實際上是’f’ ‘m’ ‘t’ ’ ‘。
FourCC的生成通常可以使用如下宏:

#define MAKE_FOURCC(a,b,c,d) \
( ((uint32_t)d) | ( ((uint32_t)c) << 8 ) | ( ((uint32_t)b) << 16 ) | ( ((uint32_t)a) << 24 ) )

在程序 中還是不要使用太長的宏爲好,在C++中可以使用模板和enum結合的方式。來保證在編譯時期就能夠將FourCC生成出來。

#define FOURCC uint32_t 
template <char ch0, char ch1, char ch2, char ch3> struct MakeFOURCC{ enum { value = (ch0 << 0) + (ch1 << 8) + (ch2 << 16) + (ch3 << 24) }; };
FOURCC fourcc_fmt = MakeFOURCC<'f', 'm', 't', ' '>::value;

將字符常量傳入模板,在結構體中聲明一個enum,編譯器會在編譯時期確定枚舉值,這樣就能給保證FOURCC在編譯就能生成出來。

WAV file

WAV 是Microsoft開發的一種音頻文件格式,它符合上面提到的RIFF文件格式標準,可以看作是RIFF文件的一個具體實例。既然WAV符合RIFF規範,其基本的組成單元也是chunk。一個WAV文件通常有三個chunk以及一個可選chunk,其在文件中的排列方式依次是:RIFF chunk,Format chunk,Fact chunk(附加塊,可選),Data chunk。
這裏寫圖片描述
一個WAV文件,首先是一個RIFF chunk;RIFF chunk又包含有Format chunk,Data chunk以及可選的Fact chunk。各個chunk中字段的意義如下:
- RIFF chunk
- id
FOURCC 值爲’R’ ‘I’ ‘F’ ‘F’
- size
其data字段中數據的大小 字節數
- data
包含其他的chunk

  • Format chunk
    • id
      FOURCC 值爲 ‘f’ ‘m’ ‘t’ ’ ‘
    • size
      數據字段包含數據的大小。如無擴展塊,則值爲16;有擴展塊,則值爲= 16 + 2字節擴展塊長度 + 擴展塊長度或者值爲18(只有擴展塊的長度爲2字節,值爲0)
    • data
      存放音頻格式、聲道數、採樣率等信息
      • format_tag
        2字節,表示音頻數據的格式。如值爲1,表示使用PCM格式。
      • channels
        2字節,聲道數。值爲1則爲單聲道,爲2則是雙聲道。
      • samples_per_sec
        採樣率,主要有22.05KHz,44.1kHz和48KHz。
      • bytes_per sec
        音頻的碼率,每秒播放的字節數。samples_per_sec * channels * bits_per_sample / 8,可以估算出使用緩衝區的大小
      • block_align
        數據塊對齊單位,一次採樣的大小,值爲聲道數 * 量化位數 / 8,在播放時需要一次處理多個該值大小的字節數據。
      • bits_per_sample
        音頻sample的量化位數,有16位,24位和32位等。
      • cbSize
        擴展區的長度
      • 擴展塊內容
        22字節,具體介紹,後面補充。
  • Fact chunk(option)
    • id
      FOURCC 值爲 ‘f’ ‘a’ ‘c’ ‘t’
    • size
      數據域的長度,4(最小值爲4)
    • 採樣總數 4字節
  • Data chunk
    • id
      FOURCC 值爲’d’ ‘a’ ‘t’ ‘a’
    • size
      數據域的長度
    • data
      具體的音頻數據存放在這裏

採用壓縮編碼的WAV文件,必須要有Fact chunk,該塊中只有一個數據,爲每個聲道的採樣總數。

Format chunk 中的編碼方式

在Format chunk中,除了有音頻的數據的採樣率、聲道等音頻的屬性外,另一個比較主要的字段就是format_tag,該字段表示音頻數據是以何種方式編碼存放的。其具體的取值可以爲以下:

  • 0x0001
    WAVE_FORMAT_PCM,採用PCM格式
  • 0x0003
    WAVE_FORMAT_IEEE_FLOAT,存放的值爲IEEE float,範圍爲[-1.0f,1.0f]
  • 0x0006
    WAVE_FORMAT_ALAW , 8bit ITU-T G.711 A-law
  • 0x0007
    WAVE_FORMAT_MULAW,8bit ITU-T G.711 μ -law
  • 0XFFFE
    WAVE_FORMAT_EXTENSIBLE,具體的編碼方式有擴展區的 sub_format字段決定

關於擴展格式塊

當WAV文件使用的不是PCM編碼方式是,就需要擴展格式塊,它是在基本的Format chunk又添加一段數據。該數據的前兩個字節,表示的擴展塊的長度。緊接其後的是擴展的數據區,含有擴展的格式信息,其具體的長度取決於壓縮編碼的類型。當某種編碼方式(如 ITU G.711 a-law)使擴展區的長度爲0,擴展區的長度字段還必須保留,只是其值設置爲0。
擴展區的各個字節的含義如下:
- size 2字節
擴展區的數據長度 ,可以爲0或22
- valid_bits_per_sample 2字節
有效的採樣位數,最大值爲採樣字節數 * 8。可以使用更靈活的量化位數,通常音頻sample的量化位數爲8的倍數,但是使用了WAVE_FORMAT_EXTENSIBLE時,量化的位數有擴展區中的valid bits per sample來描述,可以小於Format chunk中制定的bits per sample

  • channle mask 4字節
    聲道掩碼
  • sub format 16字節
    GUID,include the data format code,數據格式碼。

在Format chunk中的format_tag設置爲0xFFFE時,表示使用擴展區中的sub_format來決定音頻的數據的編碼方式。在以下幾種情況下必須要使用WAVE_FORMAT_EXTENSIBLE

  • PCM數據的量化位數大於16
  • 音頻的採樣聲道大於2
  • 實際的量化位數不是8的倍數
  • 存儲順序和播放順序不一致,需要指定從聲道順序到聲卡播放順序的映射情況。

Data chunk

Data塊中存放的是音頻的採樣數據。每個sample按照採樣的時間順序寫入,對於使用多個字節的sample,使用小端模式存放(低位字節存放在低地址,高位字節存放在高地址)。對於多聲道的sample採用交叉存放的方式。例如:立體雙聲道的sample存儲順序爲:聲道1的第一個sample,聲道2的第一個sample;聲道1的第二個sample,聲道2的第二個sample;依次類推….。對於PCM數據,有以下兩種的存儲方式:

  • 單聲道,量化位數爲8,使用偏移二進制碼
  • 除上面之外的,使用補碼方式存儲。

總結

本文主要介紹了RIFF文件的格式和WAV音頻文件格式,爲後面實現對WAVE文件的讀寫打一個理論基礎。後面打算使用C++標準庫,實現對WAV文件的讀寫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章