WebM 檔案格式
以 Matroska/EBML 為基礎、開放且免授權金的視訊容器。
- MIME 類型
- video/webm
- 副檔名
- .webm
- 分類
- 影片
Magic number(檔案簽章)
| 0x00000000 | 1A45DFA3 | ·E·· | EBML header |
開頭附近的 EBML DocType 字串是 'webm'(MKV 則是 'matroska')。
關於 WebM 格式
WebM 是 Google 為 HTML5 video 定義的免權利金容器,把 VP8、VP9 或 AV1 的畫面搭配 Vorbis 或 Opus 的聲音。與其說它是新格式,不如說它是被刻意收窄的格式:WebM 就是 Matroska 把編碼清單砍到只剩不必授權就能出貨的那些,而兩者的 EBML 編碼一個位元組都不差。EBML 是 XML 的二進位表親 — 每個元素是一個變動長度的識別碼、接一個變動長度的大小,然後不是一個值就是更多元素 — 這代表 WebM 檔案除了最前面幾個位元組之外沒有固定排版,剖析器只能一路走過去,不能直接跳著索引。檔案以 EBML 標頭開場,那是一個描述其餘部分怎麼編碼的小型 master 元素,而裡面的 DocType 字串,是唯一把 WebM 和純 Matroska 分開的欄位。
檔頭結構,一個位元組一個位元組看
| 位移 | 長度 | 欄位 | 意義 |
|---|---|---|---|
| 0 | 4 | EBML master element ID | 1A 45 DF A3。這就是全部的 magic number,而且和 Matroska 完全共用;它也是檔案裡唯一保證落在固定位置的位元組串。 |
| 4 | 1 | EBML header size | 一個變動長度整數:開頭那個 1 位元表示它只有一個位元組長,剩下七個位元是值。9F 是 31,也就是後面那段標頭本體的位元組數。寫入端可以把這個整數補到多達八個位元組,所以請把它當成一到八個位元組,而不是剛好一個。 |
| 5 | 4 | EBMLVersion element | 42 86 81 01 — 兩個位元組的元素識別碼、一個位元組的大小 1,以及值 1。EBML 標頭裡每個元素都有預設值、也都可以整個省略,所以從這裡往下的位移,是典型寫入端會產出的樣子,而不是規格釘死的位置。 |
| 9 | 4 | EBMLReadVersion element | 42 F7 81 01。讀取端至少要實作到哪個版本,才有辦法看懂這個檔案。從這個格式發表以來它一直是 1。 |
| 13 | 4 | EBMLMaxIDLength element | 42 F2 81 04。這個檔案裡最長的元素識別碼有幾個位元組。四是通用值,剖析器可以拿它來決定緩衝區大小。 |
| 17 | 4 | EBMLMaxSizeLength element | 42 F3 81 08。這個檔案裡最長的大小欄位有幾個位元組。八是標準值,也是下面講的那個「未知大小」編碼寬度是八個位元組的原因。 |
| 21 | 2 | DocType element ID | 42 82。指名這其實是哪一種以 EBML 為基礎的格式的元素,也是 WebM 檔案和 MKV 檔案光看前二十個位元組分不出來的原因。 |
| 23 | 1 | DocType length | 84 — 一個位元組的變動長度整數,值是 4,也就是後面那個字串的長度。在 Matroska 檔案裡這個位元組讀到的是 88,因為 'matroska' 有八個字元,而它後面每個位移都往後移四。 |
| 24 | 4 | DocType value | 77 65 62 6D,ASCII 的 webm 四個字母。決定格式的就是這個欄位。它前面的東西在 Matroska 檔案裡完全相同,它後面的東西排法也完全一樣。 |
| 28 | 4 | DocTypeVersion element | 42 87 81 02。寫入端用的是 WebM 元素集的哪一個版次。支援版次較低的讀取端,被期待的行為是跳過它不認得的元素,而不是直接失敗。 |
| 32 | 4 | DocTypeReadVersion element | 42 85 81 02。讀取端至少要到哪個版次才有辦法剖析這個檔案 — 這跟「看懂裡面每一個元素」是兩回事。 |
| 36 | 4 | Segment element ID | 18 53 80 67,裝著這個檔案裡每一條軌、每個 cluster、cue 和 tag 的容器,實際上就是整份內容。它的大小欄位緊接在後,而在一個正在即時寫入的檔案裡,那個大小是全部位元皆為 1 的未知形式。 |
怎麼跟長得像的格式分開
| 容易搞混的 | 怎麼分 |
|---|---|
| Matroska | 兩者是同一套編碼,差別只在位移 24 的 DocType 字串:'webm' 對上 'matroska'。還有一個更早就看得到的捷徑,在位移 4 — 因為 Matroska 的 DocType 多四個字元,那裡的 EBML 標頭大小位元組讀到的是 A3(35),WebM 則是 9F(31)。實務上的差別在編碼:Matroska 檔案可以裝 H.264、HEVC、AC-3 或 DTS,這些都不該出現在 WebM 裡,而瀏覽器即使剖析得動容器,也一樣會拒絕它們。 |
| MP4 | 結構上毫無關係。MP4 是一棵 box 樹,大小是大端序 32 位元,magic 在位移 4;WebM 是 EBML,每樣東西都是變動長度,magic 在位移 0。混淆完全發生在副檔名層級,因為兩邊都裝得下 AV1 和 Opus、也都能在現代瀏覽器裡播,所以檔案就被人在兩者之間亂改名,然後打不開。 |
| MKA | 所謂 .mka 就是一個只有音軌的 Matroska 檔案,.mks 則是只有字幕的。兩者都沒有任何能分辨的標頭位元組 — DocType 讀起來仍然是 'matroska' — 所以唯一的辦法是走進 Tracks 元素、讀每條軌的類型。純音訊的 WebM 也一樣,而那正是瀏覽器從麥克風錄音時產出的東西。 |
| Ogg | 同時代另一個免權利金容器,位元組層級毫無關係:Ogg 檔案位移 0 就是大寫 O 開頭的頁面標記 4F 67 67 53。Ogg 用一套為串流設計的 page 與 granule 結構裝 Vorbis、Opus 和 Theora,WebM 則繼承了 Matroska 的 cluster 與 cue。 |
常見的壞法
- 沒有長度的即時錄影。瀏覽器透過 MediaRecorder 錄音錄影時,不可能事先知道 Segment 會有多長,所以它寫的是未知大小形式 — 大小整數的每一個值位元都設成 1,在 EBML 正是為此允許的八位元組編碼裡就是 01 FF FF FF FF FF FF FF。這個檔案完全合法,也完全不能 seek:播放器顯示不出長度,進度條在重新封裝之前拉不動。
- 沒有 Cues。這個 seek 索引是選用元素,而串流寫入端根本沒有機會把它附加上去,所以從即時來源擷取的 WebM 從頭播得動、卻跳不了。這裡沒有任何東西壞掉;只要複製串流、順便寫出一個 Cues 元素的重新封裝,就能修好,而且不必動到任何一格壓縮後的畫面。
- 截斷。因為每個元素都宣告自己的長度,讀取端會很順地走到最後一個完整的 cluster,然後碰到一個承諾了不存在的位元組的大小。多數播放器把解得出來的部分放完就停;有些則把整個檔案報成損壞 — 所以同一個被截斷的檔案,在兩個工具裡的行為才會不一樣。
- 容器看起來對,裡面的編碼卻不對。DocType 說自己是 webm、軌裡裝的卻是 H.264 的檔案,在任何有意義的角度上都不是 WebM。它剖析得動、hex dump 看起來也乾淨,而每個瀏覽器都拒絕它 — 對不上的地方在 Tracks 元素裡的 CodecID 字串,不在標頭的任何位置。
- 前面被塞了垃圾。一頁被存成 .webm 名字的 HTML 錯誤訊息,會讓本該是 1A 45 DF A3 的地方變成看得懂的文字。跟 MP4 不同的是,WebM 裡面沒有記錄任何絕對的檔案位移可以被弄壞,所以只要把開頭那幾個位元組刪掉,檔案通常就是完整的。
這個格式現在還在用嗎
WebM 存在的理由是 H.264 要收授權費,而它在「給開放網路一個不必付錢的影片格式」這件具體任務上成功了。每個瀏覽器都播得動它,而網頁在錄螢幕、相機或麥克風時,瀏覽器產出的也是它。它完勝的場合是開放網路上的 VP9 與 AV1 交付,以及用 Opus 的音訊 — Opus 在低位元率下贏 AAC 贏得夠多,對語音來說有實質差別。它輸的則是所有牽涉到硬體和 Apple 的地方:Safari 的支援來得晚、而且一直只有一半,手機用矽晶片解 H.264、VP9 有時才有,而沒有任何電視、相機或剪輯軟體把 WebM 當一等公民。實務上網站兩種都送 — 要 WebM 的瀏覽器給 WebM,其他一律 MP4 — 而如果只能留一種,留下的還是 MP4。
在這個站上打開 WebM 檔
這些全部在你的瀏覽器裡跑,檔案不會離開你的電腦。
相關格式
容易和 WebM 搞混的格式,可以比對它們的開頭位元組。