ByteScope

AVI 檔案格式

Audio Video Interleave,Microsoft 經典的 RIFF 視訊容器。

MIME 類型
video/x-msvideo
副檔名
.avi
分類
影片

Magic number(檔案簽章)

0x0000000052494646RIFFRIFF container
0x0000000841564920AVI 'AVI ' form type

關於 AVI 格式

AVI 是 Microsoft 在 1992 年推出的視訊容器,建立在 RIFF 之上 — 跟 WAV 同一套分塊結構,每個 chunk 是一個四字元識別碼、一個小端序 32 位元長度,然後是那麼多位元組的酬載。這個設計簡單到一頁程式碼就剖析得完,而那份簡單也就是它的全部故事:AVI 沒有像樣的變動影格率概念,容器層級不支援現代音訊,沒有字幕軌,沒有每軌語言,而那個 32 位元的大小欄位在 OpenDML 擴充繞過它之前,替檔案長度訂了一個硬上限。它真正有的東西是一份完全固定的標頭,因為規格要求 'hdrl' 清單排第一、主標頭 chunk 又必須排在那份清單的第一個,所以一個 AVI 的寬、高和影格率永遠落在同樣的位元組位移上。

檔頭結構,一個位元組一個位元組看

位移長度欄位意義
04RIFF signature52 49 46 46,ASCII 的 RIFF 四個字母。它和 WAV、WebP 以及幾種同期的 Microsoft 格式共用,所以光靠它只能認出這是分塊結構,認不出是哪一種格式。
44RIFF chunk size這個欄位之後所有東西的位元組數,小端序 — 也就是檔案大小減八。AVI 裡每個大小都是小端序,這也是判斷「你看的不是 QuickTime 檔案」最快的方法。
84Form type 'AVI '41 56 49 20,尾巴那個 ASCII 空格是四字元代碼的一部分。就是這個欄位讓檔案成為 AVI 而不是 WAV 或 WebP,而那個空格也是為什麼隨手寫的字串比較會漏掉它。
124LIST identifier4C 49 53 54。RIFF 會把 chunk 分組成 list,而規格要求標頭 list 必須是檔案裡的第一個,這正是下面每個位移都可以預測的原因。
164LIST size標頭 list 的長度,小端序,含後面那個四字元的 list 類型,但不含這四個位元組本身。它涵蓋主標頭,以及每條軌一組的串流標頭區塊。
204List type 'hdrl'68 64 72 6C。指名這份 list 是標頭 list。規格要求它必須排在任何資料之前,跟 MP4 的安排剛好相反 — 這也是為什麼被截斷的 AVI 仍然報得出正確尺寸。
244Chunk identifier 'avih'61 76 69 68,AVI 的主標頭。它必須是 'hdrl' 裡的第一個 chunk,所以在格式正確的檔案裡,它永遠在這個位移上。
284avih chunk size小端序,而且固定是 38 00 00 00 — 56 個位元組,也就是後面那十四個 32 位元欄位。這裡出現任何其他值,都代表標頭壞了,或寫入端產出了不合標準的東西。
324Microseconds per frame小端序,也是容器層級唯一交代影格率的地方。00 01 86 A0 用小端序讀是 100000,也就是每秒十格。AVI 根本沒有辦法表達變動的影格率,這是這個格式後果最嚴重的限制。
364Maximum bytes per second這個檔案預期需要的尖峰資料率,單位是每秒位元組數。它原本是要讓播放器判斷媒體跟不跟得上的,今天實際上只是參考用。
404Padding granularity資料 chunk 要補齊到幾個位元組對齊 — 為 CD-ROM 播放而寫的檔案是 2048,其他幾乎所有地方是零,代表不補。這裡會列出它,是因為省略掉就會在表格裡留下一段沒有交代的四位元組空隙。
444Flags一個位元欄位:位元 4 表示檔案有索引 chunk,位元 5 表示應該用索引決定播放順序,位元 8 表示檔案是交錯排列的,位元 16 表示它是即時擷取的。真正重要的是索引那個位元,因為沒有它,seek 就退化成線性掃描。
484Total frames這個檔案的影格總數,小端序。它是編碼結束之後才寫的,所以被中斷的錄影會在這裡留下零或一個過期的值,於是即使影格全都在,播放器報出來的長度也是錯的。
524Initial frames在交錯排列的檔案裡,音訊比視訊超前幾格。只要不是從即時來源擷取的,它就是零;而一個被播放器忽略的非零值,正是整支檔案音訊固定偏移的成因之一。
564Stream count'hdrl' 裡面接著有幾組串流標頭區塊。一般情況是二,一條視訊一條音訊;格式允許更多,而舊檔案有時會帶第三條,裝著現在已經沒有東西解得開的文字或 MIDI 串流。
604Suggested buffer size寫入端認為播放器需要多大的讀取緩衝區,單位是位元組,通常是檔案裡最大那個 chunk 的大小。純參考用,而且常常是隨手填個整數 MB,而不是真的量出來的。
644Width in pixels小端序。這是容器對畫面尺寸的宣稱,而它不一定等於視訊串流自己講的 — 這兩者對不起來,在舊擷取硬體產出的檔案裡是真實存在的現象。
684Height in pixels小端序,編碼方式和寬度一模一樣。它加上位移 64 這八個位元組,是讀出 AVI 尺寸最快又可靠的方式,因為在每個合規檔案裡它們都落在固定位置。
7216Reserved四個 32 位元字組,全部是零。它們把 56 個位元組的主標頭收尾,所以下一個 chunk 從位移 88 開始 — 通常是裝著第一條串流標頭的 'strl' list。

怎麼跟長得像的格式分開

容易搞混的怎麼分
WAV同一個 RIFF 容器,位移 8 的格式類型不同:是 'WAVE'(57 41 56 45)而不是 'AVI '(41 56 49 20)。到位移 7 為止完全相同,所以只檢查前四個位元組,你只知道這是 RIFF。格式類型之後的排版就完全分岔了 — WAV 直接進 'fmt ' chunk,AVI 則開一個 'hdrl' list。
WebP也是 RIFF,位移 8 是 'WEBP'(57 45 42 50)。這個重疊乍看真的很容易搞混,因為三者的 hex dump 開頭都是同樣四個 ASCII 字母加一個小端序長度,而分開一段影片、一個音訊檔和一張靜態圖的,只有位移 8 那幾個位元組。
Matroska毫無共通之處:Matroska 位移 0 是 1A 45 DF A3,而且從頭到尾用變動長度的大小。值得把這兩者放在一起認識,是因為把舊 AVI 重新封裝成 MKV 是影格的無損複製,同時換到變動影格率、字幕軌和一份像樣的索引。
OpenDML AVI 2.0把實質上的 2 GB 與 4 GB 上限解除掉的擴充。這種檔案開頭同樣是 'RIFF' 和 'AVI ',跟上面講的一字不差,差別在後面:多出來的最上層 RIFF chunk,格式類型是 'AVIX' 而不是 'AVI ',每一個接續前面的串流。走完第一個 RIFF chunk 就停下來的讀取端,在大檔案上只會播出開頭那一段,然後把它報成「比較短」而不是「壞掉」。

常見的壞法

  • idx1 索引 chunk 不見了或被截斷。它住在檔案結尾,所以被打斷的下載或被切掉的擷取,第一個掉的就是它。影片從頭播得動,因為 chunk 本身是自我描述的,而 seek 不是直接失敗,就是退化成線性掃描,跳一次要好幾秒。
  • 2 GB 與 4 GB 那兩道牆。位移 4 的 RIFF 大小欄位是 32 位元的,所以從來不寫 OpenDML AVIX 擴充的寫入端,在檔案長過上限時就直接繞回去了。結果是一個格式正確、數字卻錯的檔案:播放器讀到的大小遠小於磁碟上的實際檔案,於是提早停住。
  • 位移 48 的影格總數寫錯。它是編碼結束時才寫的,所以當掉或被強制關閉的擷取,會留下零、或寫入端當初隨便猜的數字。每一格都在、也播得動,秀出來的長度卻是胡說八道 — 這是修標頭的事,不必重新編碼。
  • 音訊和視訊愈跑愈開。AVI 是把固定速率的 chunk 交錯排列的,所以用變動位元率編的音訊 — 這個容器從來沒為它設計過 — 會在一支長片裡對著視訊一路累積誤差。第一分鐘完全聽不出來,到第二十分鐘已經嚴重不同步,而標頭裡沒有任何線索。
  • 已經沒有人有的編碼。每條串流標頭裡的四字元代碼寫著 DIVX、XVID、MP42 或 IV50 這類東西,而其中許多解碼器早就隨著當年出貨它們的作業系統一起消失了。容器完好、每個位移也都讀得對;檔案播不出來是因為解碼器沒了,解法是轉檔而不是修復。

這個格式現在還在用嗎

AVI 是一個死不肯消失的老格式,而它至少十五年前就已經不該用在新工作上了。它的限制是結構性的、不是意外造成的 — 只有固定影格率、沒有字幕軌、沒有每軌語言、沒有現代音訊,還有一個靠擴充硬糊過去的 32 位元大小欄位 — 而 MP4 和 Matroska 把這些全部解決掉了。你還會遇到它的地方是檔案庫:攝錄影機的擷取檔、老擷取卡錄的螢幕影片、從錄影帶數位化來的影片,以及那些韌體寫完就再也沒人回頭看的科學與工業用相機。未壓縮和輕度壓縮的 AVI 在少數擷取流程裡也還在當暫存格式,因為「寫一個 chunk 加一個長度」大概是一台裝置能即時做的最便宜的事。任何需要保存下來的東西,重新封裝進 Matroska 就好:影格原封不動地複製過去,而這個容器缺的東西全部補齊。

在這個站上打開 AVI 檔

這些全部在你的瀏覽器裡跑,檔案不會離開你的電腦。

相關格式

容易和 AVI 搞混的格式,可以比對它們的開頭位元組。

格式開頭位元組副檔名
MP466 74 79 70.mp4
Matroska1A 45 DF A3.mkv
WAV52 49 46 46.wav
WebP52 49 46 46.webp

常見問題

檔案的 magic number 是什麼?

檔案開頭的前幾個位元組,不管檔名寫什麼,它標明的是真正的格式。PNG 一定以 89 50 4E 47 開頭,ZIP 則是 50 4B 03 04。作業系統、瀏覽器和 file 指令讀的都是這幾個位元組,而不是相信副檔名 — 這就是為什麼把檔案改名並不會改變它實際上是什麼。

我要怎麼自己檢查 magic number?

在 macOS 或 Linux 上,xxd -l 16 檔名 會印出前 16 個位元組;在 Windows 上,PowerShell 的 Format-Hex -Path 檔名 -Count 16。或者把檔案丟進本站的檔案類型辨識工具,它會在本機讀取位元組並告訴你是什麼格式,不會上傳任何東西。

為什麼兩種格式的 magic number 會一樣?

因為其中一種是建立在另一種之上。docx、xlsx、pptx、apk、jar 與 epub 骨子裡都是 ZIP 壓縮檔,所以全都以 ZIP 的簽章開頭;要分辨它們得看裡面的項目。Java class 檔和 macOS 的通用二進位檔都以 CA FE BA BE 開頭,靠緊接其後的欄位區分。

有完全沒有 magic number 的檔案嗎?

有。XML、HTML、JSON、SVG、CSV 這類以文字為基礎的格式沒有固定的位元組簽章,所以改用結構來辨識:開頭的 <?xml 宣告、<svg 元素,或是 { 後面接著帶引號的鍵。這種偵測是合理推測而非確定,因此本參考頁會把這些格式標示為結構偵測。

magic number 相符就代表檔案安全嗎?

不代表。它告訴你的是格式,不是內容是否無害 — 一個貨真價實的 PDF 或 docx 仍然可能夾帶惡意內容。辨識真實類型是有用的第一道檢查,尤其在副檔名和位元組不一致的時候,但它不是惡意軟體掃描。

手上有檔案可能是 AVI?用檔案類型辨識工具查出來 — 它在本機讀取 magic number,不上傳任何東西。或者瀏覽所有格式。