[轉]AVI文件格式

來源:http://blog.csdn.net/happydeer

小知識:AVI文件格式----摘自《DirectShow實務精選》 作者:陸其明

AVI(Audio Video Interleaved的縮寫)是一種RIFF(Resource Interchange File Format的縮寫)文件格式,多用於音視頻捕捉、編輯、回放等應用程序中。通常情況下,一個AVI文件可以包含多個不同類型的媒體流(典型的情況下有一個音頻流和一個視頻流),不過含有單一音頻流或單一視頻流的AVI文件也是合法的。AVI可以算是Windows操作系統上最基本的、也是最常用的一種媒體文件格式。


先來介紹RIFF文件格式。RIFF文件使用四字符碼FOURCC(four-character code)來表徵數據類型,比如‘RIFF’、‘AVI ’、‘LIST’等。注意,Windows操作系統使用的字節順序是little-endian,因此一個四字符碼‘abcd’實際的DWORD值應爲0x64636261。另外,四字符碼中像‘AVI ’一樣含有空格也是合法的。


RIFF文件首先含有一個如圖3.31的文件頭結構。

 

 

圖3.31 RIFF文件結構

 

最開始的4個字節是一個四字符碼‘RIFF’,表示這是一個RIFF文件;緊跟着後面用4個字節表示此RIFF文件的大小;然後又是一個四字符碼說明文件的具體類型(比如AVI、WAVE等);最後就是實際的數據。注意文件大小值的計算方法爲:實際數據長度 + 4(文件類型域的大小);也就是說,文件大小的值不包括‘RIFF’域和“文件大小”域本身的大小。


RIFF文件的實際數據中,通常還使用了列表(List)和塊(Chunk)的形式來組織。列表可以嵌套子列表和塊。其中,列表的結構爲:‘LIST’ listSize listType listData ——‘LIST’是一個四字符碼,表示這是一個列表;listSize佔用4字節,記錄了整個列表的大小;listType也是一個四字符碼,表示本列表的具體類型;listData就是實際的列表數據。注意listSize值的計算方法爲:實際的列表數據長度 + 4(listType域的大小);也就是說listSize值不包括‘LIST’域和listSize域本身的大小。再來看塊的結構:ckID ckSize ckData ——ckID是一個表示塊類型的四字符碼;ckSize佔用4字節,記錄了整個塊的大小;ckData爲實際的塊數據。注意ckSize值指的是實際的塊數據長度,而不包括ckID域和ckSize域本身的大小。(注意:在下面的內容中,將以LIST ( listType ( listData ) )的形式來表示一個列表,以ckID ( ckData )的形式來表示一個塊,如[ optional element ]中括號中的元素表示爲可選項。)


接下來介紹AVI文件格式。AVI文件類型用一個四字符碼‘AVI ’來表示。整個AVI文件的結構爲:一個RIFF頭 + 兩個列表(一個用於描述媒體流格式、一個用於保存媒體流數據) + 一個可選的索引塊。AVI文件的展開結構大致如下:

 

 

 

RIFF (‘AVI ’
      LIST (‘hdrl’
            ‘avih’(主AVI信息頭數據)
            LIST (‘strl’
                  ‘strh’ (流的頭信息數據)
                  ‘strf’ (流的格式信息數據)
                  [‘strd’ (可選的額外的頭信息數據) ]
                  [‘strn’ (可選的流的名字) ]
                  ...
                 )
             ...
           )
      LIST (‘movi’
            { SubChunk | LIST (‘rec ’
                              SubChunk1
                              SubChunk2
                              ...
                             )
               ...
            }
            ...
           )
      [‘idx1’ (可選的AVI索引塊數據) ]
     )

 

首先,RIFF (‘AVI ’…)表徵了AVI文件類型。然後就是AVI文件必需的第一個列表——‘hdrl’列表,用於描述AVI文件中各個流的格式信息(AVI文件中的每一路媒體數據都稱爲一個流)。‘hdrl’列表嵌套了一系列塊和子列表——首先是一個‘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;

 

然後,就是一個或多個‘strl’子列表。(文件中有多少個流,這裏就對應有多少個‘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數據結構來描述。


當AVI文件中的所有流都使用一個‘strl’子列表說明了以後(注意:‘strl’子列表出現的順序與媒體流的編號是對應的,比如第一個‘strl’子列表說明的是第一個流(Stream 0),第二個‘strl’子列表說明的是第二個流(Stream 1),以此類推),‘hdrl’列表的任務也就完成了,隨後跟着的就是AVI文件必需的第二個列表——‘movi’列表,用於保存真正的媒體流數據(視頻圖像幀數據或音頻採樣數據等)。那麼,怎麼來組織這些數據呢?可以將數據塊直接嵌在‘movi’列表裏面,也可以將幾個數據塊分組成一個‘rec ’列表後再編排進‘movi’列表。(注意:在讀取AVI文件內容時,建議將一個‘rec ’列表中的所有數據塊一次性讀出。)但是,當AVI文件中包含有多個流的時候,數據塊與數據塊之間如何來區別呢?於是數據塊使用了一個四字符碼來表徵它的類型,這個四字符碼由2個字節的類型碼和2個字節的流編號組成。標準的類型碼定義如下:‘db’(非壓縮視頻幀)、‘dc’(壓縮視頻幀)、‘pc’(改用新的調色板)、‘wb’(音縮視頻)。比如第一個流(Stream 0)是音頻,則表徵音頻數據塊的四字符碼爲‘00wb’;第二個流(Stream 1)是視頻,則表徵視頻數據塊的四字符碼爲‘00db’或‘00dc’。對於視頻數據來說,在AVI數據序列中間還可以定義一個新的調色板,每個改變的調色板數據塊用‘xxpc’來表徵,新的調色板使用一個數據結構AVIPALCHANGE來定義。(注意:如果一個流的調色辦中途可能改變,則應在這個流格式的描述中,也就是AVISTREAMHEADER結構的dwFlags中包含一個AVISF_VIDEO_PALCHANGES標記。)另外,文字流數據塊可以使用隨意的類型碼錶徵。


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


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

 

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