ByteScope

Ogg 檔案格式

Ogg 容器,常用來封裝 Vorbis/Opus 音訊或 Theora 視訊。

MIME 類型
application/ogg
副檔名
.ogg, .oga, .ogv
分類
音訊

Magic number(檔案簽章)

0x000000004F676753OggS'OggS' page capture pattern

關於 Ogg 格式

Ogg 是開放、無專利負擔的串流容器,最常裝的是 Vorbis 或 Opus 音訊,在遊戲與開源軟體中廣泛使用。每個 page 都以擷取樣式 'OggS' 開頭。那個「每個」就是整個設計的重點:Ogg 檔案不是「標頭後面接資料」,而是一串自我描述的 page,每一頁帶著自己的檢查碼、序號和串流序列號,所以解碼器可以中途插進一條即時串流,而受損的下載也能靠往前掃描下一組 4F 67 67 53 重新同步。容器本身對編碼隻字未提 — 那是由第一頁上的第一個封包決定的。

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

位移長度欄位意義
04Capture pattern 'OggS'4F 67 67 53。它標記的是一個 page 的開頭,不是檔案的開頭,所以一段一秒的音訊裡就已經有好幾十個;在 hex 編輯器裡搜尋它,找到的是整條串流的每一個 page 邊界。
41Stream structure version固定是 0。Ogg 的框架從來沒有定義過第二個版本,所以這裡是別的值,就代表這些位元組根本不是 Ogg page。
51Header type flag位元 0 表示這一頁的第一個封包是從上一頁接續下來的,位元 1 表示這是邏輯串流的開始,位元 2 表示結束。所以一個檔案的第一頁這裡讀到的是 02。
68Granule position一個小端序有號 64 位元位置,它的意義由編碼決定、不由 Ogg 決定 — Vorbis 是 PCM 取樣數,Opus 是 48 kHz 取樣數。全部位元皆為 1(-1)代表這一頁上沒有任何封包結束,所以沒有新的位置可報。
144Bitstream serial number一個小端序、接近隨機的 id,用來標明這一頁屬於哪一條邏輯串流。同時裝著影片和音訊的檔案會交錯不同序列號的 page,而串接起來的檔案則是每一段一個序列號。
184Page sequence number小端序,在每條邏輯串流裡從 0 開始數。這個號碼跳號,正是解碼器判斷「掉了一頁」而不是「資料損壞」的依據。
224Page checksum對整個 page 算出來的 CRC-32,計算時這個欄位暫時歸零,用的是多項式 0x04C11DB7,輸入輸出都不反轉,最後也不做 XOR — 這是刻意不跟 ZIP 和 gzip 用的那個 CRC-32 一樣,好讓兩者不會被搞混。
261Number of page segments分段表有幾筆,0 到 255。它讓一個 page 的上限是 27 + 255 + 255 x 255 = 65307 個位元組,這也是為什麼不管編碼怎麼做,Ogg 的延遲都有上界。
27variableSegment table每個分段一個位元組,值是 0 到 255。一個封包的長度是一路累加下去,直到出現一個小於 255 的值才結束,所以剛好是 255 永遠代表「還沒完」。每個手寫的 Ogg 剖析器都是在這裡出錯的。
variablevariableFirst packet — the codec identification header緊接在分段表之後,所以在只有一個分段的第一頁上就是位移 28。Vorbis 寫 01 後面接 'vorbis',Opus 寫 'OpusHead',Ogg 裡的 FLAC 寫 7F 後面接 'FLAC',Theora 寫 80 後面接 'theora'。這裡、而不是副檔名,才是這段音訊真正的身分。

怎麼跟長得像的格式分開

容易搞混的怎麼分
oga/ogv/opus在容器層級根本沒有東西可以分辨:這四個副檔名用的都是同一套 'OggS' 框架,而慣例只是說 .oga 是音訊、.ogv 是影片、.opus 是 Opus 串流。答案永遠在分段表後面的識別封包 — 純 Vorbis 檔案位移 28 是 01 加 'vorbis',Opus 則是位移 28 的 'OpusHead'。改檔名什麼都改變不了,相信 MIME type 也一樣。
FLACFLAC 有兩層皮,而且很容易搞混。原生 FLAC 位移 0 就是 66 4C 61 43,然後直接進一個 34 位元組的 STREAMINFO 區塊。裝在 Ogg 裡的 FLAC 跟其他東西一樣以 4F 67 67 53 開頭,而 7F 46 4C 41 43 這個標記出現在位移 28,後面接一個對應版本、一個標頭封包數,然後才是原生的 'fLaC' 標記和它的 STREAMINFO。
WebM另一個無專利負擔的開放容器,也是大家在問「該用哪一個」時通常的另一個選項。WebM 和 Matroska 是 EBML 文件,開頭是 1A 45 DF A3,跟 'OggS' 一個位元組都不共用。影片在瀏覽器裡是 WebM 贏了;Ogg 守住了 Vorbis 和 Opus。
MP3MP3 是沒有容器的裸音框串流,開頭不是一個 'ID3' 標籤就是一個十一位元全設的音框同步。它沒有 page 檢查碼、沒有序號,也沒有辦法通報掉了一個音框 — 而那正是 Ogg 當初為串流而生要補的缺口。

常見的壞法

  • 即時串流裡掉了一頁。Ogg 把這件事當成正常而不是致命的:位移 18 的序號跳號,解碼器回報一段空缺,然後在下一個擷取樣式的位置繼續播。部分損壞的下載也是同一套救法 — 往前掃描 4F 67 67 53,從那裡接下去。
  • 被截斷、而且沒有結束串流的那一頁。因為最後一頁永遠沒被設上標頭類型旗標的位元 2,沒有東西交代最終的 granule 位置,所以總長度是未知的。音訊會把收到的部分播完,而進度條和報出來的長度一直是錯的。
  • page 內容位元腐蝕。位移 22 的 page 檢查碼對不上,解碼器丟掉的是整個 page — 零點幾秒的音訊 — 而不是整個檔案。損壞聽起來是一聲喀,後面每一頁的驗證照樣通過。
  • 隨手串接。用 `cat` 把兩個 Ogg 檔案接起來,得到的是一條合法的鏈式串流、帶著兩個不同的序列號,但非常多播放器會停在第一個結束串流的 page,只報出第一個檔案的長度。解法是重新封裝,不是串接。
  • 前面被塞了位元組。一段 HTTP 錯誤內容或被黏在前面的 ID3 標籤,會把第一個擷取樣式擠離位移 0。每一頁都完好無缺,會重新同步的播放器照樣找得到它們,但一個只讀位移 0 的偵測器會把這個檔案報成不明格式。

這個格式現在還在用嗎

Ogg 今天的任務比從前窄,但站得非常穩。Vorbis 是當年對抗 MP3 的自由答案,至今仍是極大量遊戲與開源應用程式封裝音訊的方式,因為在 MP3 還有專利包袱的年代它沒有。Opus 標準化在 RFC 6716,檔案用 Ogg 裝、通話用 RTP 送,如今是 WebRTC 的預設語音編碼,也是現存最好的通用低延遲音訊編碼 — 所以 Ogg 從編碼大戰裡走出來時,裡面裝的正是贏家。影片這一塊,這個容器輸給 WebM 和 MP4 輸得很徹底,.ogv 實際上已經是歷史名詞。讓 Ogg 仍是第一選擇的,是那種必須在丟包中活下來的串流:page 是自我描述、帶檢查碼、而且可以重新同步的,所以解碼器可以中途加入即時串流,也能在掉了一個封包之後自行復原,完全不需要任何帶外訊號。

在這個站上打開 Ogg 檔

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

相關格式

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

格式開頭位元組副檔名
MP349 44 33.mp3
FLAC66 4C 61 43.flac
WebM1A 45 DF A3.webm

常見問題

檔案的 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 仍然可能夾帶惡意內容。辨識真實類型是有用的第一道檢查,尤其在副檔名和位元組不一致的時候,但它不是惡意軟體掃描。

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