AVI格式分析

AVI文件採用的是RIFF文件結構方式,RIFF(Resource Interchange File Format,資源互換文件格式)是微軟公司定義的一種用於管理windows環境中多媒體數據的文件格式,波形音頻wave,MIDI和數字視頻AVI 都採用這種格式存儲。構造RIFF文件的基本單元叫作數據塊(Chunk),每一個數據塊包含3個部分,windows

  一、4字節的數據塊標記(或者叫作數據塊的ID)緩存

  二、數據塊的大小數據結構

  三、數據工具

  整個RIFF文件能夠當作一個數據塊,其數據塊ID爲RIFF,稱爲RIFF塊。一個RIFF文件中只容許存在一個RIFF塊。 RIFF塊中包含一系列的子塊,其中有一種字塊的ID爲"LIST",稱爲LIST,LIST塊中能夠再包含一系列的子塊,但除了LIST塊外的其餘全部 的子塊都不能再包含子塊。編碼

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

  一、4字節的數據塊標記(Chunk ID)orm

  二、數據塊的大小視頻

  三、4字節的形式類型或者列表類型索引

  四、數據資源

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

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

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

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

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

從上面的圖上能夠看到另外一種特殊的數據塊,用一個四字符碼'JUNK'來表徵,它用於內部數據的隊齊(填充),應用程序應該忽略這些數據塊的實際意義。

 

下面仔細的介紹每一個子塊的內容:

2.1信息塊

信息塊包含兩個子塊,即一個ID爲 avih 的子塊和一個ID 爲 strl 的LIST塊。

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

typedef struct

{

FOURCC fcc;     // 必須爲'avih'
    DWORD    cb;      // 本數據結構的大小,不包括最初的8個字節(fcc和cb兩個域)

 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 _avistreamheader {
          FOURCC fcc;    // 必須爲'strh'
          DWORD    cb;     // 本數據結構的大小,不包括最初的8個字節

          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;

上圖是一個strh塊的內容,73 74 72 68是strh,是此塊的標示符,後面緊跟着此塊的大小00 00 00 38,後面四字節是vids(綠色部分),表明着視頻幀,注意後面是編碼的類型,此處爲H264,如紅色框所示。

 

  "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;

 WORD nChannels; //聲道數

 DWORD nSamplesPerSec; //採樣率

 DWORD nAvgBytesPerSec; //聲音中每秒的數據量

 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"

壓縮的圖像數據流

能夠看到數據塊是以movi爲開始,而後是音視頻標示符+塊大小,依次存放,每一個塊以四字節的標示符爲開始,可表現爲list---size----movi---00db---size---01wb---size----00db---

,其中音視頻流的順序不固定。

avi文件的圖像數據能夠是壓縮的,和非壓縮格式的。對於壓縮格式來講,也可採用不一樣的編碼,也許你曾經遇到有些avi無法識別,就是由於 編碼方式不同,若是沒有相應的解碼,你就無法識別視頻數據。AVI的編碼方式有不少種,比較常見的有 mpeg2,mpeg4,divx等。

 

2.2 索引塊

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

typedef struct

{

 DWORD ckid; //記錄數據塊中子塊的標記

 DWORD dwFlags; //表示chid所指子塊的屬性

 DWORD dwChunkOffset; //子塊的相對位置

 DWORD dwChunkLength; //子塊長度

}; 

 index段是能夠沒有的,視頻同樣能夠播放。但是當你要拖動視頻時,視頻不會馬上跳到你所要的位置,而是加快播放速度,直到到達目標位置。而有索引段時可直接到達所要的位置。

 

3 拓展

根據實際文件咱們看一下索引部分的結構。

首先是idx1的標示符69 64 78 31,其次是整個索引塊的大小,4byte,下面就是具體的音頻流、視頻流的信息,首先是流的標示符,30 30 64 62,如圖紅色框所示,是00db表明視頻流,後面藍色框的四字節是表明是不是關鍵幀,10 00 00 00是關鍵幀,不是關鍵幀用00 00 00 00,後面紫色框是塊的偏移地址,此地址是針對數據塊的movi的標示符,最後灰色框中的四字節表明此塊的大小。

 

 

下面看一下這個偏移地址

首先找到movi的地址是0x1F0+C=0x1FC,第一個00db塊的地址是0x200,如圖中粉色線所示,其偏移量是0x200-0x1fc=0x04

注:這裏面的數須要高低位轉換,例如此處00db塊的大小是E0 72 00 00,實際大小應該是0x000072E0。

 

下面咱們驗證一下第二個塊的偏移地址是否正確。

能夠看到第二個塊的地址是0x74E8,則偏移地址是0x74E8-0x1fc=0x72EC,則對應的值應該是EC 72 00 00,查看一下上面索引截圖裏面的偏移值確實也是此值。

 

 

經過RIFF結構咱們能夠看到數據區中都是以視頻流、音頻流間隔存放的,可是間隔又不相同。其實,這個是沒有什麼實際的關係,即便把全部 的視頻流放在一塊兒,而後下面纔是音頻流,也是能夠工做的,此時只須要更改一下索引表。能夠經過UltraEdit工具直接右擊打開avi文件進行修改。

還能夠發現一個avi文件中通常只有一個LIST:movi,此時能夠人爲的添加一個LIST:movi,在其放置一些音頻流和視頻流,並須要修改索引表,此時偏移地址只能以第一個movi的位置爲準,不然沒法解析,不能正常播放。

相關文章
相關標籤/搜索