ByteScope

M4A 檔案格式

MPEG-4 音訊,通常是 AAC 編碼,裝在 ISO-BMFF 容器裡。

MIME 類型
audio/mp4
副檔名
.m4a
分類
音訊

Magic number(檔案簽章)

0x0000000466747970ftypISO-BMFF 'ftyp' box
0x000000084D344120M4A brand 'M4A '

關於 M4A 格式

M4A 是裝在 MP4 容器裡的 AAC(或 ALAC)音訊,也是 iTunes 與 Apple Music 下載所用的格式。它是 ISO-BMFF 檔案,'ftyp' 品牌識別為 'M4A '。ISO-BMFF 是一棵 box 樹,每個 box 是一個大端序 32 位元大小加一個四字元類型,整套結構文法就這樣而已 — 'ftyp' 宣告這個檔案講的是哪種方言,'moov' 是讓它播得動的索引,'mdat' 裝著編碼後的音框。因為索引和資料是分開的兩個 box,一個 M4A 可以逐位元完好無缺,卻只因為掉了錯的那一頭就完全播不出來。

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

位移長度欄位意義
04ftyp box size大端序,而這件事值得多停留一下:ISO-BMFF 檔案裡所有東西都是大端序,跟 RIFF 完全相反。典型值是 00 00 00 1C,也就是 28 個位元組。大小是 1 代表類型欄位後面跟著 64 位元的 largesize;大小是 0 代表這個 box 一路延伸到檔案結尾。
44Box type 'ftyp'66 74 79 70。它坐在位移 4 而不是 0,是因為大小排在前面 — 這就是為什麼每個 MP4 家族的偵測器都是往內四個位元組去比對,也是為什麼這個家族裡沒有任何格式的 magic number 落在檔案最前面。
84Major brand4D 34 41 20 — 字母 M4A 加一個尾隨空格,因為品牌識別永遠是四個字元。光是這個欄位,就是 M4A、MP4('isom' 或 'mp42')、M4V、3GP('3gp4')、AVIF('avif')和 HEIC('heic')之間唯一的差別。
124Minor version一個大端序的版本號,是品牌識別的版本、不是檔案格式的版本。Apple 血統的檔案傳統上帶 00 00 02 00、也就是 512,而規格要讀取端忽略它,不要把它當成相容性門檻。
16variableCompatible brands一串四位元組的品牌識別,把 ftyp box 剩下的空間填滿 — 常見的是 'M4A '、'isom'、'iso2'。看不懂主要品牌識別的播放器,只要認得這串清單裡任何一個,就仍然可以播這個檔案 — 新格式能繼續被舊軟體打開,靠的就是這個。
variable8Next box header從 ftyp 的大小所說的位置開始 — 一個 major brand 加三個 compatible brands 這種常見組合就是 28 — 一樣是四個位元組的大小接四個位元組的類型。真實檔案接下來放的是 'free'、'moov' 或 'mdat',所以 ftyp box 之後沒有任何位移是固定的。
variablevariable'moov' box索引:軌列表、時間刻度、長度、編碼設定,以及把每個音框對應到位元組位移與時間戳的樣本表。沒有它什麼都播不了,而它合法地可以放在檔案的任一端。
variablevariable'mdat' box編碼後的音框本身,內部沒有任何索引 — 它就是一堆位元組,只有 'moov' 裡的樣本表才賦予它們意義。它自己的位置也不固定:28 個位元組的 ftyp 後面接一個 8 位元組的 'free' box,'mdat' 就從位移 36 開始,'moov' 則從 mdat 的長度用完的地方接下去。
variable4Codec four-character code inside 'moov'埋在樣本描述裡:AAC 是 'mp4a',Apple Lossless 是 'alac'。在一個品牌識別寫著 M4A 的檔案裡兩者都合法,所以品牌識別告訴你的是容器方言,而這個欄位才告訴你音訊究竟是什麼。

怎麼跟長得像的格式分開

容易搞混的怎麼分
MP4前八個位元組一個不差,之後的結構也一個不差。位移 8 的品牌識別就是全部差別:'M4A ' 對上 'isom' 或 'mp42'。更麻煩的是,很多純音訊檔案是用 'isom' 品牌識別寫出來的,所以光靠品牌識別無法證明裡面沒有影片 — 要證明就得走進 'moov' 去數軌。
QuickTime MovieQuickTime 正是 ISO-BMFF 標準化的來源,所以 box 文法是同一套。現代的 .mov 位移 8 帶的是 71 74 20 20('qt ',尾隨兩個空格),而且通常在 ftyp 後面就有一個 'wide' box — 那是 MP4 的寫入端不會產出的東西。這個組合才是可靠的判別點。
3GP又是同一個容器,位移 8 的品牌識別是 '3gp4'、'3gp5' 或 '3gpp'。實務上的差別在允許裝什麼:3GP 的設定檔把編碼限縮在行動網路談定的那些,所以一個結構上完全合法的 MP4,仍然可能被只認 3GP 的解碼器拒收。
ADTS AAC裸的 .aac 檔案完全沒有 box。它是一串裸的 ADTS 音框,每一框以一個十二位元的同步字開頭,所以檔案開頭是 FF F1 或 FF F9。裡面的音訊可能就是 M4A 裝的那條 AAC 位元串流,但沒有 ftyp、沒有 moov、也沒有 seek 表,它就完全是另一種檔案了。
MP3老是被搞混,因為兩者都是「你買來的壓縮音訊」,但 MP3 是一串裸音框,開頭是一個 'ID3' 標籤或一個音框同步,而且它沒有容器、沒有樣本表,除了 ID3 標籤之外也沒有標準辦法帶封面圖。它前十六個位元組跟 ISO-BMFF 的 box 沒有半點相似。

常見的壞法

  • 索引在錯的那一頭,加上下載被截斷。除非特別要求搬家,編碼器都是先寫 'mdat'、最後才寫 'moov',所以一個停在 95% 的下載裝著幾乎全部的音訊、卻一點索引都沒有,結果是任何東西都播不出哪怕一秒。跑一次 faststart 把 'moov' 搬到前面,正是串流伺服器堅持要這麼做的原因。
  • 'mdat' 前面被插入或刪掉位元組。樣本表存的是絕對的檔案位移,所以在前面黏一個 ID3 標籤、或把多出來的前綴剝掉,都會一次讓每一個音框指標失去同步。跟 ZIP 不同 — ZIP 的讀取端還能自己算出偏移量 — MP4 完全不會給你任何位移已經移動的訊號,播出來就是雜訊或什麼都沒有。
  • box 大小小於 8,或在檔案中間出現 0。相信這個欄位的剖析器,不是在一個長度為零的 box 上永遠迴圈,就是走出緩衝區之外;經過強化的讀取端會直接拒收任何小於 8 的大小,而這是媒體函式庫上經典的 fuzzing 目標。
  • 四 GB 的 chunk 位移之牆。一般的 chunk 位移表是 32 位元的,所以超過四 GB 的檔案必須改用 64 位元的變體。從來不寫它的寫入端,產出的檔案後段位移會繞回去,於是一段長錄音播到一半就突然壞掉。
  • 文字模式傳輸。編碼音框內部的換行轉換,不會影響 box 樹的剖析,所以檔案會報出正確的長度和編碼,然後播出一片靜電雜訊 — 中介資料一點事都沒有,因為損壞全在 'mdat' 裡面。

這個格式現在還在用嗎

現在買來的和串流聽的音樂,實際上就是 M4A。Apple 把它做成 iTunes 的下載格式,而 MP4 容器裡的 AAC 如今是 Apple 生態系、YouTube 的音軌、多數 podcast 訂閱源,以及兩大手機平台語音備忘錄的預設;同一個容器裡的 ALAC 則負責無損那一層。它幾乎在所有新東西上取代了 MP3,因為同樣位元率下 AAC 明顯更好,也因為這個容器帶來的是真正的中介資料、章節和封面圖,而不是硬掛在尾巴上的一個標籤。它不是第一選擇的場合是任何對延遲敏感、或走開放技術棧的東西:Ogg 或 WebM 裡的 Opus 在低位元率下贏過 AAC,而且沒有授權包袱,所以語音聊天和 WebRTC 都往那邊走了。後製工作則根本沒有人在編輯 M4A — 大家是解碼成 WAV、編輯完再編碼一次,因為 AAC 是有損的,每重編一次傷害就疊一層。

在這個站上打開 M4A 檔

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

相關格式

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

格式開頭位元組副檔名
MP349 44 33.mp3
MP466 74 79 70.mp4
FLAC66 4C 61 43.flac

常見問題

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

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