avi規範

RIFF文件規範

Peter Lee 2007-10-02

 

摘要:RIFF全稱爲資源互換文件格式(Resources Interchange File Format),RIFF文件是windows環境下大部分多媒體文件遵循的一種文件結構,常見的如WAV文件、AVI文件等。RIFF可以看成一種樹狀結構,其基本組成單元爲LIST和CHUNK,分別如樹的節點和葉子。

 

一、RIFF文件簡介

RIFF是Microsoft提出的一種多媒體文件的存儲方式,不同編碼的音頻、視頻文件,可以按照它定義的存儲規則保存、記錄各自不同的數據,如:數據內容、採集信息、顯示尺寸、編碼方式等。在播放器或者其它提取工具讀取文件的時候,就可以根據RIFF的規則來分析文件,合理的解析出音頻、視頻信息,正確進行播放。常見的RIFF文件有WAV文件和AVI文件,它們都是遵循RIFF格式保存播放信息和播放數據的。

 

二、RIFF文件的組織結構

在RIFF的文件存儲規則中,主要有幾個重要的概念需要理解,它們是FOURCC,CHUNK, LIST。下面會對這幾個概念進行詳細解釋。

RIFF格式是一種樹狀的結構,其基本組成單元爲LIST和CHUNK,分別如樹的節點和葉子。RIFF格式也類似windows文件系統的組織形式,windows文件系統有目錄和文件,分別對應RIFF中的LIST和CHUNK。Windows文件系統中的目錄可以包含子目錄和文件,而文件是保存數據的基本單元,RIFF也使用了這樣的結構。在RIFF文件中,數據保存的基本單元是CHUNK,可用於保存音視頻數據或者一些參數信息,LIST相當於文件系統的目錄,可以包含多個CHUNK或者多個LIST。

1FOURCC

一個FOURCC(four character code)是一個佔4個字節的數據,一般表示4個ASCII字符。在RIFF文件格式中,FOURCC非常普遍,LISTtype,chunkid, 起始標識等信息都是用FOURCC表示的。FOURCC一般是四個字符,如”abcd”這樣的形式,也可以三個字符包含一個空格,如”abc ”這樣的形式。

2CHUNK

一個CHUNK數據塊的數據結構如下:

ChunkID ChunkSize ChunkData

ChunkID是一個FOURCC,標識該CHUNK的名稱,類似於windows文件系統中的文件名。 ChunkSize佔用4個字節,表示ChunkData部分的數據內容大小,以字節爲單位。ChunkData則是CHUNK中實質性的內容,保存的是CHUNK的具體數據內容。一個CHUNK保存的數據可以是關於聲音文件的編碼方式、音視頻採樣等信息,也可以是音頻或視頻數據。具體表示是哪類數據則通過ChunkID來標識。

3LIST

一個LIST數據塊的數據結構如下:

“LIST” ListSize ListType ListData

“LIST”也是一個FOURCC,而且是固定的,每個LIST都是以“LIST”爲開頭。ListSize佔用4個字節,表示ListType和ListData兩部分加在一起的大小。ListType是一個FOURCC,是對LIST具體包含的數據內容的標識。而ListData則是該LIST的數據內容區,有CHUNK和子LIST組成,它們的個數和組成次序可以是不確定的。

4RIFF文件頭

RIFF文件頭的數據結構如下:

“RIFF” FileSize FileType FileData

“RIFF”也是一個FOURCC,用於標識該文件是一個RIFF格式的文件。FileSize是一個4字節的數據,給出文件的大小,但僅包括FileType和FileData兩部分。FileType是一個FOURCC,用來說明文件類型,如”WAV”, “AVI”等。FileData部分表示文件的具體內容,可以是LIST也可以是CHUNK.

 

三、RIFF文件舉例——WAV文件

WAV是waveform(波形)的所寫,該聲音文件是一個典型的按照RIFF規則組織的文件。一般,在一個WAV文檔中,主要用到RIFF文件頭和CHUNK塊兩個概念。圖1所示爲windows自帶錄音器所錄製一段WAV語音文件的結構圖。這個文件主要由三個CHUNK組成,它們的名稱分別是:”fmt”,”fact和””data”,前兩個CHUNK包含的是編碼、回放等信息,”data”CHUNK包含的是語音數據。


圖1 WAV示例文件結構圖

 

四、RIFF解析器——RIFFspot

RIFFspot用樹方式直觀展現wav,avi等RIFF文件的結構信息,圖2爲RIFFspot截圖。


圖2 RIFFspot截圖

 


AVI文件規範

PeterLee 2007-10-14

一、AVI文件簡介

AVI的英文全稱爲Audio VideoInterleaved,即音頻視頻交錯格式,是將語音和影像同步組合在一起的文件格式。AVI於1992年被Microsoft公司推出,隨Windows3.1一起被人們所認識和熟知。AVI文件格式多用於音視頻捕捉、編輯、回放等應用程序中。通常情況下,一個AVI文件可以包含多個不同類型的媒體流(典型的情況下有一個音頻流和一個視頻流),不過含有單一音頻流或單一視頻流的AVI文件也是合法的。AVI可以算是Windows操作系統上最基本的、也是最常用的一種媒體文件格式。

Note: 本文介紹的是基本的AVI文件格式規範,至於newAVI等一些AVI擴展格式,請關注筆者後續文章。

二、RIFF文件規範

AVI文件屬於一種RIFF(ResourceInterchange File Format的縮寫)文件格式,與此同類的還有常見的WAV文件。RIFF是Microsoft提出的一種多媒體文件的存儲方式,不同編碼的音頻、視頻文件,可以按照它定義的存儲規則保存、記錄各自不同的數據。如果讀者不熟悉RIFF文件規範,閱讀下面章節前,建議先閱讀《RIFF文件規範》這篇文章:http://blog.csdn.net/sunshine1314/archive/2007/10/10/1817991.aspx

三、AVI文件結構實例分析

1、AVI文件結構示例

       圖1所示爲windows系統目錄下的clock.avi的文件結構圖,其結構是用RIFFspot程序解析得到的,關於RIFFspot程序,感興趣的讀者可以到下面的網址中下載:http://blog.csdn.net/sunshine1314/archive/2007/09/22/1795739.aspx

圖1clock.avi文件結構

2、AVI文件全局結構說明

       如圖1所示,整個AVI文件的結構爲:一個RIFF頭 + 兩個列表(一個用於描述媒體流格式、一個用於保存媒體流數據) + 一個可選的索引塊 + 一個JUNK塊。

首先,RIFF (‘AVI’…)表徵了AVI文件類型。然後就是AVI文件必需的第一個列表——‘hdrl’列表,用於描述AVI文件中各個流的格式信息(AVI文件中的每一路媒體數據都稱爲一個流)。‘hdrl’列表嵌套了一系列塊和子列表——首先是一個‘avih’塊,用於記錄AVI文件的全局信息。然後,就是一個或多個‘strl’子列表。文件中有多少個流,這裏就對應有多少個‘strl’子列表,示例clock.avi文件有兩路流,既音頻流和視頻流。

當AVI文件中的所有流都使用一個‘strl’子列表說明了以後(注意:‘strl’子列表出現的順序與媒體流的編號是對應的,比如第一個‘strl’子列表說明的是第一個流(Stream 0),第二個‘strl’子列表說明的是第二個流(Stream 1),以此類推),‘hdrl’列表的任務也就完成了,隨後跟着的就是AVI文件必需的第二個列表——‘movi’列表,用於保存真正的媒體流數據(視頻圖像幀數據或音頻採樣數據等)。

最後,緊跟在‘hdrl’列表和‘movi’列表之後的,就是AVI文件可選的索引塊。這個索引塊爲AVI文件中每一個媒體數據塊進行索引,並且記錄它們在文件中的偏移(可能相對於‘movi’列表,也可能相對於AVI文件開頭)。

圖1中還有一種特殊的數據塊,用一個四字符碼‘JUNK’來表徵,它用於內部數據的隊齊(填充),應用程序應該忽略這些數據塊的實際意義。

3、’avih’塊

‘avih’塊,用於記錄AVI文件的全局信息,比如流的數量、視頻圖像的寬和高等,可以使用一個AVIMAINHEADER數據結構來操作: 

typedef struct_avimainheader {
    FOURCC fcc;   // 必須爲‘avih’
    DWORD  cb;    // 本數據結構的大小,不包括最初的8個字節(fcc和cb兩個域)
    DWORD  dwMicroSecPerFrame;   // 視頻幀間隔時間(以毫秒爲單位)
    DWORD  dwMaxBytesPerSec;     // 這個AVI文件的最大數據率
    DWORD  dwPaddingGranularity; // 數據填充的粒度
    DWORD dwFlags;         // AVI文件的全局標記,比如是否含有索引塊等
    DWORD  dwTotalFrames;   // 總幀數
    DWORD  dwInitialFrames; // 爲交互格式指定初始幀數(非交互格式應該指定爲0)
    DWORD  dwStreams;      // 本文件包含的流的個數
    DWORD  dwSuggestedBufferSize; // 建議讀取本文件的緩存大小(應能容納最大的塊)
    DWORD dwWidth;         // 視頻圖像的寬(以像素爲單位)
    DWORD dwHeight;        // 視頻圖像的高(以像素爲單位)
    DWORD  dwReserved[4];   // 保留
} AVIMAINHEADER;

4、’strl’子列表

每個‘strl’子列表至少包含一個‘strh’塊和一個‘strf’塊,而‘strd’塊(保存編解碼器需要的一些配置信息)和‘strn’塊(保存流的名字)是可選的。首先是‘strh’塊,用於說明這個流的頭信息,可以使用一個AVISTREAMHEADER數據結構來操作: 

typedef struct _avistreamheader{
     FOURCC fcc;  // 必須爲‘strh’
     DWORD  cb;   // 本數據結構的大小,不包括最初的8個字節(fcc和cb兩個域)
     FOURCC fccType;    //流的類型:‘auds’(音頻流)、‘vids’(視頻流)、
                  //‘mids’(MIDI流)、‘txts’(文字流)
     FOURCC fccHandler; // 指定流的處理者,對於音視頻來說就是解碼器
     DWORD  dwFlags;    // 標記:是否允許這個流輸出?調色板是否變化?
     WORD   wPriority;  // 流的優先級(當有多個相同類型的流時優先級最高的爲默認流)
     WORD   wLanguage;
     DWORD  dwInitialFrames; // 爲交互格式指定初始幀數
     DWORD  dwScale;   // 這個流使用的時間尺度
     DWORD  dwRate;
     DWORD  dwStart;   // 流的開始時間
     DWORD  dwLength;  // 流的長度(單位與dwScale和dwRate的定義有關)
     DWORD  dwSuggestedBufferSize; // 讀取這個流數據建議使用的緩存大小
     DWORD  dwQuality;    // 流數據的質量指標(0 ~ 10,000)
     DWORD  dwSampleSize; // Sample的大小
     struct {
         short int left;
         short int top;
         short int right;
         short int bottom;
}  rcFrame;  // 指定這個流(視頻流或文字流)在視頻主窗口中的顯示位置
             // 視頻主窗口由AVIMAINHEADER結構中的dwWidth和dwHeight決定
} AVISTREAMHEADER;

 

然後是‘strf’塊,用於說明流的具體格式。如果是視頻流,則使用一個BITMAPINFO數據結構來描述;如果是音頻流,則使用一個WAVEFORMATEX數據結構來描述。

5、‘movi’列表

‘movi’列表保存的是真正的媒體流數據,其數據組織方式有兩種。可以將數據塊直接嵌在‘movi’列表裏面,也可以將幾個數據塊分組成一個‘rec ’列表後再編排進‘movi’列表。

當AVI文件中包含有多個流的時候,數據塊與數據塊之間如何來區別呢?數據塊使用了一個四字符碼來表徵它的類型,這個四字符碼由2個字節的類型碼和2個字節的流編號組成。標準的類型碼定義如下:‘db’(非壓縮視頻幀)、‘dc’(壓縮視頻幀)、‘pc’(改用新的調色板)、‘wb’(音縮視頻)。比如第一個流(Stream 0)是音頻,則表徵音頻數據塊的四字符碼爲‘00wb’;第二個流(Stream 1)是視頻,則表徵視頻數據塊的四字符碼爲‘00db’或‘00dc’。對於視頻數據來說,在AVI數據序列中間還可以定義一個新的調色板,每個改變的調色板數據塊用‘xxpc’來表徵,新的調色板使用一個數據結構AVIPALCHANGE來定義。(注意:如果一個流的調色板中途可能改變,則應在這個流格式的描述中,也就是AVISTREAMHEADER結構的dwFlags中包含一個AVISF_VIDEO_PALCHANGES標記)。另外,文字流數據塊可以使用隨意的類型碼錶徵。

   注意:視頻數據塊在類型碼之後的四個字節一般是數據長度,讀取真正的視頻幀時要注意把其去掉,音頻數據塊同樣有四字節的頭,讀取數據時也要注意去掉,如果是音頻是立體音(雙聲道),則數據塊裏含有左右聲道的數據,按採樣字節長度交叉填充。

 

6、AVI索引塊

索引塊使用一個四字符碼‘idx1’來表徵,索引信息使用一個數據結構來AVIOLDINDEX定義。 

typedef struct _avioldindex {
   FOURCC  fcc;  // 必須爲‘idx1’
   DWORD   cb;   // 本數據結構的大小,不包括最初的8個字節(fcc和cb兩個域)
   struct _avioldindex_entry {
      DWORD   dwChunkId;   // 表徵本數據塊的四字符碼
      DWORD  dwFlags;     // 說明本數據塊是不是關鍵幀、是不是‘rec’列表等信息
      DWORD   dwOffset;    //本數據塊在文件中的偏移量
      DWORD  dwSize;      // 本數據塊的大小
  } aIndex[]; // 這是一個數組!爲每個媒體數據塊都定義一個索引信息
} AVIOLDINDEX;

 注意:如果一個AVI文件包含有索引塊,則應在主AVI信息頭的描述中,也就是AVIMAINHEADER結構的dwFlags中包含一個AVIF_HASINDEX標記。

四、後記

       大家應該都聽過“AVI文件不適合用於流媒體傳輸”這樣的說法,通過本文對AVI文件結構的解析,相信大家對這種說法有更清晰的驗證,因爲AVI文件結構中置於文件尾部的索引塊、頭部信息中規定的文件長度等過多的選項都是不適合流媒體應用的。

 

 

AVI是音頻視頻交錯(Audio Video Interleaved)的英文縮寫,它是Microsoft公司開發的一種符合RIFF文件規範的數字音頻與視頻文件格式,原先用於Microsoft Video for Windows (簡稱VFW)環境,現在已被Windows 95/98OS/2等多數操作系統直接支持。AVI格式允許視頻和音頻交錯在一起同步播放,支持256色和RLE壓縮,但AVI文件並未限定壓縮標準,因此,AVI文件格式只是作爲控制界面上的標準,不具有兼容性,用不同壓縮算法生成的AVI文件,必須使用相應的解壓縮算法才能播放出來。常用的AVI播放驅動程序,主要是Microsoft Video for WindowsWindows 95/98中的Video1,以及Intel公司的Indeo Video

  在介紹AVI文件前,我們要先來看看RIFF文件結構。AVI文件採用的是RIFF文件結構方式,RIFFResourceInterchange File Format,資源互換文件格式)是微軟公司定義的一種用於管理windows環境中多媒體數據的文件格式,波形音頻waveMIDI和數字視頻AVI都採用這種格式存儲。構造RIFF文件的基本單元叫做數據塊(Chunk),每個數據塊包含3個部分,

14字節的數據塊標記(或者叫做數據塊的ID

2、數據塊的大小

3、數據

  整個RIFF文件可以看成一個數據塊,其數據塊IDRIFF,稱爲RIFF塊。一個RIFF文件中只允許存在一個RIFF塊。RIFF塊中包含一系列的子塊,其中有一種字塊的ID"LIST",稱爲LISTLIST塊中可以再包含一系列的子塊,但除了LIST塊外的其他所有的子塊都不能再包含子塊。

RIFFLIST塊分別比普通的數據塊多一個被稱爲形式類型(Form Type)和列表類型(List Type)的數據域,其組成如下:

14字節的數據塊標記(Chunk ID

2、數據塊的大小

34字節的形式類型或者列表類型

4、數據

  下面我們看看AVI文件的結構。AVI文件是目前使用的最複雜的RIFF文件,它能同時存儲同步表現的音頻視頻數據。AVIRIFF塊的形式類型是AVI,它包含3個子塊,如下所述:

1、信息塊,一個ID"hdrl"LIST塊,定義AVI文件的數據格式。

2、數據塊,一個ID "movi"LIST塊,包含AVI的音視頻序列數據。

3、索引塊,ID "idxl"的子塊,定義 "movi"LIST塊的索引數據,是可選塊。

AVI文件的結構如下圖所示,下面將具體介紹AVI文件的各子塊構造。

1、信息塊,信息塊包含兩個子塊,即一個ID avih的子塊和一個IDstrlLIST塊。


"avih"子塊的內容可由如下的結構定義:

typedef struct
{
DWORD dwMicroSecPerFrame ; //顯示每楨所需的時間ns,定義avi的顯示速率
DWORD dwMaxBytesPerSec; // 最大的數據傳輸率
DWORD dwPaddingGranularity; //記錄塊的長度需爲此值的倍數,通常是2048
DWORD dwFlages; //AVI文件的特殊屬性,如是否包含索引塊,音視頻數據是否交叉存儲
DWORD dwTotalFrame; //文件中的總楨數
DWORD dwInitialFrames; //說明在開始播放前需要多少楨
DWORD dwStreams; //文件中包含的數據流種類
DWORD dwSuggestedBufferSize; //建議使用的緩衝區的大小,
//通常爲存儲一楨圖像以及同步聲音所需要的數據之和
DWORD dwWidth; //圖像寬
DWORD dwHeight; //圖像高
DWORD dwReserved[4]; //保留值
}MainAVIHeader;


"strl"LIST塊用於記錄AVI數據流,每一種數據流都在該LIST塊中佔有3個子塊,他們的ID分別是"strh","strf", "strd"
"strh"
子塊由如下結構定義。

typedef struct
{
FOURCC fccType; //4字節,表示數據流的種類 vids表示視頻數據流
//auds 音頻數據流
FOURCC fccHandler;//4字節,表示數據流解壓縮的驅動程序代號
DWORD dwFlags; //數據流屬性
WORD wPriority; //此數據流的播放優先級
WORD wLanguage; //音頻的語言代號
DWORD dwInitalFrames;//說明在開始播放前需要多少楨
DWORD dwScale; //數據量,視頻每楨的大小或者音頻的採樣大小
DWORD dwRate; //dwScale /dwRate = 每秒的採樣數
DWORD dwStart; //數據流開始播放的位置,以dwScale爲單位
DWORD dwLength; //數據流的數據量,以dwScale爲單位
DWORD dwSuggestedBufferSize; //建議緩衝區的大小
DWORD dwQuality; //解壓縮質量參數,值越大,質量越好
DWORD dwSampleSize; //音頻的採樣大小
RECT rcFrame; //視頻圖像所佔的矩形
}AVIStreamHeader;


"strf"子塊緊跟在"strh"子塊之後,其結構視"strh"子塊的類型而定,如下所述;如果 strh子塊是視頻數據流,則 strf子塊的內容是一個與windows設備無關位圖的BIMAPINFO結構,如下:

typedef struct tagBITMAPINFO
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1]; //顏色表
}BITMAPINFO;

typedef struct tagBITMAPINFOHEADER
{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
}BITMAPINFOHEADER;


  如果 strh子塊是音頻數據流,則strf子塊的內容是一個WAVEFORMAT結構,如下:

typedef struct
{
WORD wFormatTag; //編碼類型 1爲PCM
WORD nChannels; //聲道數
DWORD nSamplesPerSec; //採樣率
DWORD nAvgBytesPerSec; //WAVE聲音中每秒的數據量
WORD nBlockAlign; //數據塊的對齊標誌
WORD biSize; //此結構的大小
}WAVEFORMAT


"strd"子塊緊跟在strf子塊後,存儲供壓縮驅動程序使用的參數,不一定存在,也沒有固定的結構。

"strl"LIST塊定義的AVI數據流依次將 "hdrl " LIST塊中的數據流頭結構與"movi" LIST塊中的數據聯繫在一起,第一個數據流頭結構用於數據流0,第二個用於數據流1,依次類推。

  數據塊中存儲視頻和音頻數據流,數據可直接存於 "movi" LIST塊中。數據塊中音視頻數據按不同的字塊存放,其結構如下所述,

  音頻字塊
"##wb"
Wave 數據流
  視頻子塊中存儲DIB數據,又分爲壓縮或者未壓縮DIB
"##db"
RGB數據流
"##dc"
  壓縮的圖像數據流

  看到了吧,avi文件的圖像數據可以是壓縮的,和非壓縮格式的。對於壓縮格式來說,也可採用不同的編碼,也許你曾經遇到有些avi沒法識別,就是因爲編碼方式不一樣,如果沒有相應的解碼,你就沒法識別視頻數據。AVI的編碼方式有很多種,比較常見的有 mpeg2mpeg4divx等。

索引塊,索引快包含數據塊在文件中的位置索引,能提高avi文件的讀寫速度,其中存放着一組AVIINDEXENTRY結構數據。如下,這個塊並不是必需的,也許不存在。

typedef struct
{
DWORD ckid; //記錄數據塊中子塊的標記
DWORD dwFlags; //表示chid所指子塊的屬性
DWORD dwChunkOffset; //子塊的相對位置
DWORD dwChunkLength; //子塊長度
};

 

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