音声ファイルを解剖する

@kfurumiya

2021/05/27

自己紹介

古都こと

@kfurumiya

stand.fm エンジニア

HN

Twitter

所属

最近使ってる言語

趣味

最近やってるゲーム

TypeScript / Rust

ゲーム / お絵描き / プログラミング

原神 / アークナイツ

stand.fm

  • 手軽にできる音声配信サービス
  • Podcastのような収録配信
  • 複数人でのLIVE配信

エンジニア募集中です

https://corp.stand.fm/recruit

今日の献立

  • メディアコンテナ
  • WAV
  • MP4
  • Ogg
  • Matroska

今日は触れないこと

  • 音声の具体的な符号化方式

メディアコンテナ

  • 音声の波形が直接ファイルに書き込まれることは少ない
  • 一般的に「コンテナ」という構造をとる
  • 複数のデータ構造を直列に繋いだ形式が多い

コンテナ

メタデータ

音声データ

さまざまな

データ

WAVファイル

  • リニアPCMで使われるコンテナ
  • 実はコンテナ形式なのでMP3なども入れられる
    • 現実で見たことはないが…
  • 各々のデータの呼び名は「チャンク」
    • fmtチャンク:dataチャンクの形式が書いてある
    • dataチャンク:音声データ

WAV(RIFF)コンテナ

fmt

data

MP4コンテナ

  • 主にaacなどを格納するマルチメディアコンテナ
  • 音声だけでなく動画トラックやテキストトラックなども入る
  • 昔懐かしのQuickTime形式がベース
  • 各々のデータの呼び方は「ボックス」
    • QT形式の名残で「atom」と呼ばれることが多い(ffmpegとか)
    • 子ボックスを持てるのでツリー構造にできる

MP4コンテナ

ftyp

moov

mdat

MP4コンテナ

  • ボックスの種類はめちゃくちゃ多い(一部のみ掲載)
    • ftyp:ファイルタイプ
    • moov:メタデータ。多層の入れ子になっている
    • mdat:メディアデータ
    • ユーザ定義ボックス:ユーザ側で定義したカスタムデータ
  • ボックスの順番に特に決まりはない
    • ftypが1番目なのは固定
  • 複数の音声や動画が存在できる
    • moovに各メディア(トラック)の情報が入っている

MP4コンテナ

  • メタデータ+データというシンプルな形式でわかりやすい
  • 一枚岩のデータになるので破損に弱い
    • moov(メタデータ)欠けるとmdatをデコードできなかったり…
    • 最低限ftyp+moov+mdatがないと厳しい
  • ストリーミングには弱い
    • 全部揃い切ってからエンコードしないといけない
    • mdatが確定しないとmoov書き出すのが厳しい
    • HLS(HTTP Live Streaming)である程度解決はする

Oggコンテナ

  • 主にopusなどを格納するマルチメディアコンテナ
    • 音声:Vorbis, Opus, FLACなど
    • 動画:Theoraなど
  • データを細切れに「パケット」で格納する
  • 送信時は「ページ」に詰めて送る
  • 送受信が前後したり多重化しててもオッケー
  • ネット越しにやりとりしやすい形式

Oggコンテナ

パケット

パケット

パケット

Matroskaコンテナ

  • だいたいなんでも入る(音声・動画)
  • 拡張子の「mkv」とか「mka」は見たことある人もいるのでは
  • 直接使うことは少ないがWebMのベースになっている
  • EBMLというXMLのバイナリ版で表現
    • 任意のバイナリタグと任意の子要素
  • 特性としてはOggと似たような感じ
    • EBMLのおかげで拡張性はこっちの方が高いかも

OGGコンテナ

EMBL Node

EMBL Node

EMBL Node

EMBL Node

まとめ

  • 音声ファイルには音声データが直接入っているわけではない
    • 複数の構造体の集合である「コンテナ」という形式を取る
  • コンテナの構造はいろいろ
    • シンプルなメタデータ+データのMP4
    • データを細切れにしてストリーミングしやすいOggやMatroska
  • 単一音声だけでなく複数音声や動画も入れられるコンテナも多い
    • マルチメディアコンテナ
  • 何かトラブルにあったときはこの構造を思い出してみるといいかも?
    • 完全に破損してなくて一部だけ取り出せたりとか
    • 逆に破損復帰できなさそうだから諦める選択が取れたりとか