Matroska 檔案格式
Matroska,一個幾乎能容納任何編碼的開放多媒體容器。
- MIME 類型
- video/x-matroska
- 副檔名
- .mkv
- 分類
- 影片
Magic number(檔案簽章)
| 0x00000000 | 1A45DFA3 | ·E·· | EBML header |
開頭附近的 EBML DocType 字串是 'matroska'。
關於 Matroska 格式
Matroska 是一開始就打算什麼都裝得下的開放容器:任何視訊編碼、任何音訊編碼、數量不限的字幕軌、章節、附件、標籤,以及每條軌各自的語言,全部裝在同一個檔案裡。它建立在 EBML 之上 — 一種形狀像 XML 的二進位編碼,每個元素是一個變動長度的識別碼,接一個變動長度的大小,然後不是一個值就是巢狀的元素。因為大小是明講而不是推導出來的,剖析器可以在完全看不懂任何一個元素的情況下把整個 Matroska 檔案走完,不認得的東西直接跳過。WebM 是同一套編碼配上一份比較小的編碼清單,所以兩者的前二十一個位元組完全相同,唯一的差別是指名格式的那個 DocType 字串。
檔頭結構,一個位元組一個位元組看
| 位移 | 長度 | 欄位 | 意義 |
|---|---|---|---|
| 0 | 4 | EBML master element ID | 1A 45 DF A3,magic number,也是這個檔案裡唯一由規格、而不是由慣例釘死位置的欄位。WebM 這裡是一模一樣的四個位元組。 |
| 4 | 1 | EBML header size | 一個變動長度整數,開頭那個 1 位元表示它只有一個位元組長,剩下七個位元給出標頭本體的大小。Matroska 檔案是 A3、也就是 35,WebM 則是 9F、也就是 31 — 差的那四個位元組正是 'matroska' 比 'webm' 多出來的長度。寫入端可以把這個整數補到多達八個位元組。 |
| 5 | 4 | EBMLVersion element | 42 86 81 01 — 元素識別碼、大小 1、值 1。這份標頭裡每個元素都有預設值、也都可以合法省略,所以下面這些位移描述的是一般寫入端實際吐出來的樣子,不是規格保證的排版。 |
| 9 | 4 | EBMLReadVersion element | 42 F7 81 01。讀取端至少要實作到哪個 EBML 版本才剖析得了這個檔案。它從來沒離開過 1。 |
| 13 | 4 | EBMLMaxIDLength element | 42 F2 81 04。這個檔案裡任何地方用到的最長元素識別碼,實務上是四個位元組,剖析器可以據此在開工前把緩衝區大小定下來。 |
| 17 | 4 | EBMLMaxSizeLength element | 42 F3 81 08。這個檔案裡最長的大小欄位。八是常見值,也是即時寫入的 Segment 上那個未知大小標記寬度是八個位元組的原因。 |
| 21 | 2 | DocType element ID | 42 82。指名這個檔案實際上是哪一種以 EBML 為基礎的格式,也是 Matroska 檔案光看前二十個位元組跟 WebM 分不出來的唯一原因。 |
| 23 | 1 | DocType length | 88 — 一個位元組的變動長度整數,值是 8,也就是後面那個字串的長度。WebM 這裡是 84,因為它的名字只有四個字元,而從這裡開始,兩種格式後面每個位移都差四。 |
| 24 | 8 | DocType value | 6D 61 74 72 6F 73 6B 61,ASCII 的 matroska。決定格式的就是這個欄位,也是為什麼檔案類型檢查至少得讀三十二個位元組、不能只讀四個。 |
| 32 | 4 | DocTypeVersion element | 42 87 81 04。寫入端用的是 Matroska 元素集的哪一個版次 — 4 涵蓋了現在多數封裝器依賴的新增內容。讀取端被期待跳過不熟悉的元素,而不是拒收檔案。 |
| 36 | 4 | DocTypeReadVersion element | 42 85 81 02。要能剖析這個檔案,至少需要哪個版次 — 這個數字刻意比上面那個版本低,好讓比較舊的讀取端不會被關在門外。 |
| 40 | 4 | Segment element ID | 18 53 80 67,裝著整個檔案本體的 master 元素:軌定義、一團團的影格 cluster、cue 索引、章節、標籤和附件。它的大小緊接在後,而在還在寫入中的檔案裡,它是未知大小形式。 |
怎麼跟長得像的格式分開
| 容易搞混的 | 怎麼分 |
|---|---|
| WebM | 同一套編碼,位移 24 換個名字:'matroska' 對上 'webm'。早一個位元組的判別更快 — 位移 23 的 DocType 長度這裡是 88、那裡是 84 — 而位移 4 的 EBML 標頭大小也因為同一個原因不同,A3 對上 9F。真正重要的是編碼:Matroska 裝得下 H.264、HEVC、AC-3、DTS 和 TrueHD,而這些從一個標成 WebM 的檔案裡拿出來,瀏覽器一個都不會解。 |
| MKA | .mka 是只裝音訊的 Matroska 檔案,.mks 只裝字幕,.mk3d 則是立體視覺的。沒有一個帶著可供分辨的標頭位元組 — DocType 每次讀到的都是 'matroska' — 所以副檔名只是寫入端對內容的宣稱,而真相唯一被記錄下來的地方是 Tracks 元素。 |
| MP4 | 結構上毫無關係:MP4 是一棵 box 樹,大小是大端序 32 位元,位移 4 是 'ftyp';Matroska 是 EBML,識別碼和大小都是變動長度,magic 在位移 0。它們老是被拿來比較,是因為兩邊都裝得下 H.264 和 AAC,而且互相重新封裝是無損複製,但它們的位元組沒有任何共通之處。 |
| AVI | Matroska 當初就是為了取代它而生的容器。AVI 是 RIFF,大小是小端序,開頭是 52 49 46 46、位移 8 是 'AVI ',而且它對變動影格率、現代音訊、字幕或每軌語言都沒有像樣的支援。把舊 AVI 重新封裝成 MKV,壓縮後的影格一個位元組都不變,卻把上面那些全部拿到手。 |
常見的壞法
- 未知的 Segment 大小從來沒被補回去。封裝器寫進管線或即時來源時,會把 Segment 大小整數的每個值位元都設起來 — 那是 EBML 正是為此定義的全 1 形式 — 並且照理應該在收工時回頭寫上真正的長度。中途被砍掉,它就永遠沒寫 — 留下一個從頭播得動、報不出長度、也不能 seek 的檔案。
- 少了 Cues 元素。這個 seek 索引通常放在 Segment 的頭或尾,而即時擷取的東西根本不會有它。播放器只能退回去掃 cluster,在大檔案上又慢又不準;單純重新封裝一次就會寫出一份像樣的索引,而且一格畫面都不必重壓。
- 截斷。每個元素都寫明自己的長度,所以讀取端會乾淨地走到最後一個完整的 cluster,然後碰上一個承諾了不存在的位元組的大小。有些播放器把到那個點為止的東西播完就停;有些則說整個檔案壞了 — 所以一個下載到一半的 MKV 才會在某個工具裡打得開、在另一個裡打不開。
- 字幕文字編碼不對。容器會記錄每條軌的 CodecID 和語言,但對比較舊的文字格式來說,並不會記錄一個可靠的字元編碼。一條用 Big5、GBK 或 Shift-JIS 寫的字幕軌被當成 UTF-8 讀,就會出來一堆亂碼,而影片和音訊的每個位元組都好好的。
- 元素識別碼壞掉。因為識別碼和大小都是變動長度的,大小欄位裡翻掉一個位元組,就能讓剖析器跳進某個影格中間、把垃圾當成下一個元素來讀。這種檔案往往還是播得動,因為 cluster 會重新同步,但嚴格的剖析器會停在翻掉的那個點,把後面全部報成讀不了。
這個格式現在還在用嗎
Matroska 是影片拿來保存、而不是拿來交付的地方。任何帶多國語言音軌、好幾條字幕軌、章節和內嵌字型的東西都是 MKV,因為沒有別的容器能毫無怨言地處理這種組合,而且重新封裝進去只是把影格無損複製一次,不是重新編碼。它也是多數編碼工具的工作格式,所以就算內容明明塞得進 MP4,從那些工具出來的檔案照樣是 .mkv。它輸的地方是覆蓋率:沒有瀏覽器播得動它,iOS 和多數電視拒收,硬體播放器的支援又參差不齊,所以只要東西是要寄給別人的,安全答案仍然是 MP4。慣例做法是用 Matroska 典藏、匯出成 MP4,而因為裡面的影片完全沒被動過,那個匯出只是換容器,不是畫質損失。
在這個站上打開 Matroska 檔
這些全部在你的瀏覽器裡跑,檔案不會離開你的電腦。
相關格式
容易和 Matroska 搞混的格式,可以比對它們的開頭位元組。