動画においてMP3音声トラックの音ずれには、さまざまな原因がある。VBRの問題は広く知られている。 この文書では「LAMEタグ」と「MP3の量子化誤差」(エンコーダーディレイ)という、あまり知られていない二つの問題について考える。
動画でlame.exeを普通に使うと「LAMEタグ非対応」のMP3デコーダーでは、映像/字幕に対して音声が約50ms遅れ、 音声の末尾は削られてしまう。原因は「LAMEタグ」であり、 動画用のMP3作成では-tスイッチを使ってこれを抑止するべきだ。
この文書は、従来の動画作成の定石であった lame --preset cbr 160 のようなコマンドラインを否定し、 さらに -t スイッチを追加しなければならないと主張するものです。 大筋では間違いないと思われますが、これまでの常識を否定する内容なだけに、 慎重な検討・検証が必要です。 間違っている可能性もあります。 しばらくの間、この記事の内容は暫定的な試案ととらえてください。
中間報告 (2005年11月10日) 現時点でのテスト(確定ではない)では、 この問題はMP3のデコーダーに依存し、コンテナには依存しない(MKVでもAVIでも同じになる)。 そして、次のデコーダーが「LAMEタグの副作用」を受ける度合いが高い: Media Player Classic内蔵デコーダー(libmad系)、 ffdshowのlibmad、mpg123dsfのMAD。次のデコーダーは「LAMEタグの副作用」を受けにくいか、またはLAMEタグを正しく解釈する: Windowsのデフォルト(IIS)、ffdshowのmp3lib、 mpg123dsfのmpg123、mplayer。 すなわちLAMEタグを使った場合には再生環境によって音声の同期が異なり、 タイミングの再現性が保証されない。特にMAD系は常にLAMEタグの副作用を受けるように思われる。 LAMEタグを使わない場合、再生環境に(ほぼ)依存せずに音声の同期を確保できる。したがって、 やはり-t推奨説を採用する。 ただし、確定した結論を出すには、さらに多様かつ精密なテストが必要である。 (なおVLCは今回はテスト自体が失敗した。)
2006年2月4日 追記 WavDestを使った実際の計測により「動画ではLAMEタグを使うと高確率で音ずれする」と断定する。 一方、デコーダーの違いによる結果の差は、検証できなかった。 「libmadよりmp3libの方がLAMEタグを正しく処理できる」という予想は、経験的にはある程度根拠があるのだが、 客観的に検証できなかった。詳細は「動画音声のlame -tについて: WavDestによる検証」。
2009年3月10日 追記 説明の仕方の細部はともかく、この記事の内容自体は正しい。 動画用のMP3では -t スイッチの使用を強く推奨する。 追加の参考資料、 Finding Zeros Sample in Lame MP3 Frame Header, Finding zero sample in mp3 file using hex editor to estimate silence (HydrogenAudio)
次のような3秒間ちょうどのWAVファイルを考える。 サンプリング周波数は48000 Hzとしよう。
経過秒数 | 内容 |
---|---|
0.000~1.000 | 無音 |
1.000~2.000 | 音 |
2.000~3.000 | 無音 |
これを通常の設定でLAME MP3にし、 「LAMEタグ」非対応のツールでデコードすると、次のような状態になる。
経過秒数 | 内容 |
---|---|
0.000~1.047 | 無音 |
1.047~2.046 | 音 |
2.046~3.072 | 無音 |
「音」の出だしが本来より47ms程度遅れ、3秒きっかりで終わる映像クリップと合体させると音声ファイルの末尾72msほどが削られてしまう。
このことは、オーディオエディタで実際に波形を見ることで、容易に確認できる。
変換元の 3sec48.wav は、3秒ちょうどの長さで、1.000~2.000秒の1秒間のみ、電子音が鳴っている。
lame --preset cbr 160 3sec48.wav 3sec48.mp3
上記によってMP3圧縮すると、
音の出だしが47~48ms遅くなった。lame のバージョンは 3.97 beta 1 である。
ビデオの1フレームは23.976fpsにて約42msなので、 このままでは音声と映像の同期が、ビデオの1コマ分以上ずれていることになり、好ましくない。 ただし、これは lame のバグではない。 「LAMEタグ」と言って、見かけ上ずれているようだが、対応プレーヤーで再生すると、 この「LAMEタグ」の働きで逆に再生時間が極めて正確になる(詳細は後述)。 しかし、非対応プレーヤーで再生すると、見たままのずれが生じる。
lame --preset cbr 160 -t 3sec48.wav 3sec48t.mp3
このように -t スイッチを追加すると、音ずれは23~24msに緩和された。
ビデオの1フレームを42msと考えると、24msは一応、許容範囲と言える。LAMEタグへの対応・非対応と無関係に同じタイミングで再生される。 後述のようにこの±24msの誤差はMP3の規格上、避けられない(映像と合体させる段階で補正できるケースもあるが、 一般には補正できない)。
サンプルを公開するので、興味ある方は実際に試してみてほしい。
3sec48.zip 284KB
標準のMP3規格では、圧縮元のWAVファイルの長さを正確に再現できない。 LAMEではこの問題を解決するハックを使うが、このハックの副作用として、上記の問題が生じる。
MP3は基本的にWAVの1152サンプルずつを1グループとして処理するので、
WAVに比べて時間の解像度が1000倍以上も悪い。
毎秒48000サンプルでは、オーディオの1フレームが24msとなる。
1/48000×1152 = 0.024(秒)
WAV自身は、1/48000秒すなわち約0.02msの解像度があるのだから、
24ms単位の入れ物では正確な長さが再現できない。
これを解決するハックとして、LAMEは実際の音声データの直前に、 ダミーフレームを挿入し、そこにLAME Tagと呼ばれるメタ情報を格納する。 foobar2000などの対応プレーヤーでは、このメタ情報を利用して、MP3を正確な長さで再生することができる。 すなわち、冒頭と末尾については、 1フレーム=1152サンプルより細かい精度(1サンプル単位)で無音部分の長さを調整でき、 理論上、変換元と完全に同じ再生時間にできる。本来20ms程度の解像度しかないのに、 全体の長さについてはCDと同じ0.02msオーダーの精度を実現するのだから、これ自体としては素晴らしいハックと言える。
一方、LAMEタグを理解できない一般のデコーダーからは、この特別なフレームは単なる無音の水増しフレームに見える。 当然、LAMEタグに基づく末尾の無音の微調整も行われない。 したがって、LAMEタグ非対応のデコーダーは、
オーディオ単体のファイルは冒頭や末尾の無音の長さが0.1秒変わったところでほとんどの場合、実害がない(そもそも分からない)だろう。 ところが、動画の音声成分としてMP3を使う場合、話はやっかいだ。 動画作成上は、当然のことながら「1コマのずれもなく、映像と音声がちゃんと同期している」状態にしたい。 ところが、映像の1コマは24fpsでも約42msだから、LAMEタグを使うと「ちゃんと同期」しないのだ。 非対応デコーダーにとってのLAMEタグの水増しは50ms程度で、ずれの量が1コマより長いからだ。
LAMEタグの具体的な数値情報は、foobar2000で、
MP3ファイルのプロパティとして見ることができる。冒頭の例では次のように表示された。
enc_delay = 576
enc_padding = 1729
mp3_accurate_length = yes
LAMEタグを使った場合、 もし再生側がそれに完全対応していれば、映像と音声の同期は、理論上0.02msオーダーの驚異的な精度となる。 しかし対応している可能性は低いと思われる。 対応していないと、音声と映像の同期に50ms程度のずれが生じる。
動画には不必要な0.02msの精度にこだわった結果、かえって50msもずれては話にならない。 AC3などの音ずれを1ms単位で補正した努力も水の泡となってしまう。
一方、0.02msの精度を捨てても、代償となる不正確さは24msのオーダーであり、典型的なビデオの1フレーム(約42ms)より十分に短いから、 こちらは無視できる。 さらに、0.02msの同期精度も理論値に過ぎず、ビデオをレンダリングするハードウェア側において、現実には不可能だろう。
LAMEタグが解釈されないと、確実に映像の1フレーム以上、音ずれする。特にデリケートなタイミングを行っているカラオケなどでは深刻であり、 一般にも、爆発音や全力疾走する人の足音など、鋭い立ち上がりエッジの音は、映像との1フレームの非同期が問題となりうる。
LAMEタグを使った場合、 ビデオが終了したらオーディオをそこでカットする設定になっていると(VirtualDubModのデフォルトである)、 本来の音声トラックの末尾が削れてしまう。末尾が無音ならいいが、次回予告などで最後の一瞬まで早口でしゃべりまくるようなパターンでは、 末尾が削れると現実的な影響が生じる。
LAMEタグは、冒頭と末尾の無音の長さをサンプル単位で制御できるだけで、 全般的な量子化の粒度は向上しない。 グルーピングした1152サンプルの途中で激しい音の変化がある場合などには、 そのタイミングは依然、あいまいになる。 MP3には、仕様上、あくまで24msの解像度しかない。 LAMEタグに起因する50msオーダーの音ずれはLAMEタグを使わないことで回避できるが、 それでもなお、24msオーダーの不正確さは残る。
この問題は、対音声の字幕同期においてカラオケでは問題になりうるが、 より一般的な対映像の音声同期については、典型的なビデオ(24/25/30fps)では1フレームが33~42msのオーダーだから、 24msの粒度は一応十分である。24ms単位の途中で起きること、つまり10msオーダーにこだわるなら、 人間の耳とスピーカーが数メートル離れているだけでも同じオーダーの影響がある(音速は約340メートル/秒だから)。 したがって、スピーカーとの距離まで指定するのでない限り、10msのオーダーにこだわる意味はほとんどない。
結局、一般的な動画作成を問題にしている限りにおいて、 LAMEタグを無効化することによる精度の低下があるとしても、それはすべて無視できる範囲に吸収できてしまう。 一方、LAMEタグを有効化することによる副作用がある場合、それは無視できない問題を生じさせるのである。
典型的な精度の順序
MP3のフレーム(24ms)<ビデオのフレーム(33~42ms)<LAMEタグの影響(40~60ms)
注1: ビデオ1フレームは、23.976fpsでは約42msに達するので、 LAMEタグの影響が40msなら不等号が逆転するように見えるかもしれない。 しかしLAMEタグで水増しされる40~60msは常にマイナス方向のディレイで一方的に誤差を増大させるのに対して、 ビデオのフレームの精度は±42msの範囲という精度保証なので、同列には論じられない。 ここでは、おおざっぱなイメージとして、 LAMEタグの影響はビデオの1フレームとほぼ等しいか、それよりやや大きいと理解すれば良い。
注2: 1152サンプルが24msになるのは、48000 Hzの場合であり、 サンプリング・レートが低ければもっと粗い解像度になる。 例えば32000 Hzでは36msである。ダウンサンプリングを行うと、周波数の範囲が狭くなって音質が低下するだけでなく、 このように、MP3では時間解像度も粗くなる。 36msの解像度があれば、24fpsならビデオの1フレームの精度がぎりぎり確保できるが、 それ以下のサンプリング・レートでは、MP3の時間軸の量子化誤差が、ビデオの1コマの長さを超えてしまう。
当分の間、動画作成ではLAMEタグを使うべきではない。根拠は、
よって、 LAMEで動画用のMP3を作るときは、VBRでもCBRでも、 -tスイッチによってLAMEタグを明示的に禁止することを推奨する。
例:
lame --preset cbr 160 -t in.wav out.mp3
これは動画の音声部分に使うMP3の場合であって、一般のMP3では、 特に理由がない限り、-tスイッチを使うべきではない。
この問題へのもう一つの対応法としては、 「LAMEタグを使用して、見かけ上の水増しの分を、後からmux時に補正する」という考え方もある。 しかし、水増しの長さが予期しにくいうえ、補正を忘れたり間違いが生じやすいというデメリットがあるうえ、 LAMEタグを使っても使わなくても、事実上、音質の違いはないのだから、LAMEタグを最初から使わない方が良い。
さらに非対応ツールから見ると、LAMEタグを含むMP3は変換元WAVより長くなっているように見える。 したがって、映像と音声をいくつかの部分に分けて、別々に編集して、後からつなげるような場合、 LAMEタグの使用には特に注意が必要であり、避けた方が良い。
動画から音声部分を抜き出すとき、それがLAMEタグを持つMP3である場合には、 その動画の同期が、LAMEタグを前提にしているか、それとも、LAMEタグの誤差を前提にしているかを決定しなければならない。 通常、後者であると思われる。したがって、取り出したMP3を、 foobar2000のようなLAMEタグを正しく解釈できるツールでWAVにデコードすると、本来とタイミングが異なる。 この場合は、LAMEタグを正しく解釈できることで、かえってタイミングが狂うので注意を要する。
一般に、LAMEタグを持つMP3を基準に対音声のタイミング(カラオケなど)を行う場合、 タイミング・ツール(またはその前処理となるMP3デコード・ツール)がLAMEタグを解釈するかしないかの違いで、 まったく同じMP3を使っているのに、違う時間軸になる。このあいまいさによる混乱を避けるためにも、 動画用のMP3では、LAMEタグ不使用を推奨する。
LAMEタグを使ったMP3は変換元WAVより50msほど遅れる(DVD2AVIなどの符号の付け方で言えば、マイナス方向のディレイがある)。 LAMEタグを使わなくても、MP3には(冒頭の無音部分の長さという意味で)24~36ms程度の量子化誤差がある。 LAMEタグ非対応ツール(対応ツールの方が珍しい)では、LAMEタグがあると、LAMEタグの水増し部分とMP3の量子化誤差の相乗効果で、 0.1秒程度の音ずれが生じる可能性がある。
SabbuやSub Station Alphaのように「WAVでないとタイミングできないツール」で字幕作成、特にカラオケ作成をした場合、 後からWAVをLAMEでMP3圧縮すると、上記のように、字幕の対音声同期で20~100ms程度のずれが生じる可能性があり、 繊細なタイミング作業が台無しになる。
SSA/ASSのタイミングは10msの解像度があるから、MP3の量子化誤差は無視できない。 ましてLAMEタグの水増しがあると、対音声タイミングのずれが、映像の1フレームを超過する。 これは、字幕の対映像タイミングが変わってしまうことを意味する。
したがって、「WAVでないとタイミングできないツール」を使う場合、 いったん最終的な音声形式(この例ではMP3)に音声ファイルを変換した上で、 それをWAVにデコードしたファイルを使って、タイミング作業を行うことが望ましい。
VBR options: ... -t disable writing LAME Tag -T enable and force writing LAME Tag
ヘルプではVBRのオプションに分類されているが、CBRでも使える。 なお、--decodeのときは、-tスイッチは別の意味(WAVヘッダを書かない)になる。
LAME MP3を動画の音声として使うときは、-tスイッチによって、LAMEタグを抑止することが望ましい。 さもないと、高確率で映像と音声が1フレームずつずれる。
注意: この文書はLAMEの音質について論じるものではない。 動画の音声部分にLAMEを使うとき、音声トラックと他のトラック(映像・字幕)の同期に関して発生するLAME特有の問題を、検証している。 -tを付けないと音質が悪くなるとか、 動画以外の一般の用途で-t必要だという意味ではないので、誤解のないようにお願いします。
MP3圧縮のとき、 アルゴリズム上、音声は一定の時間的区分(例 24ms)を単位で処理され、したがって全体としては、 どんな時間的長さでも許されるわけでなく、原則として、 その単位の整数倍の長さ(飛び飛びの値)しかとれない。 このように飛び飛びの値しかとれず、そのような飛び飛びの値で近似することを一般に「量子化」というが、デジタル音声処理では「量子化」という言葉は、 周波数成分の量子化に限って使う習慣がある。したがって、混乱を避けるため、以下では「量子化」という言葉は避け、 時間軸が単位長(24msなど)の倍数に切り上げられること、 つまり時間方向の離散化のことを、単に「離散化」と呼ぶことにする。 そして、実際の入力はその値でないのに離散化によって切り上げられることで時間の長さが少し変わってしまうことを「離散化誤差」と呼ぶことにする。 これは必ずしも一般的な用語ではなく、以下の説明を簡潔にするための便宜上の用語である。
一般のMP3は、離散化誤差により冒頭の無音の長さなどが微妙に変わる。 LAMEでは、LAMEタグというハックによって、デフォルトでこの問題に対応しており、 LAMEタグ対応デコーダーでは、冒頭の無音の長さが正確になる。 一方、LAMEタグ非対応のデコーダーからは、LAMEタグは無意味なパディングに見え、 LAMEタグのせいで、冒頭の無音の長さが増大し、不正確さがかえって増える。 とはいえ、曲頭の無音が0.05秒程度増えたところで、通常の音楽の再生では、まったく問題ないだろう。
LAMEタグと冒頭無音部の関係をまとめると、次のようになる。
動画の音声にLAMEを使うとき、最後のケースでの約48msの遅れは、 通常の動画の1フレーム(~42ms)より大きいので、注意を要する。 音だけを再生するときは、出だしの無音が0.1秒増えたところで実害はないが、 映像と同期させているときは、出だしの無音が増えるとは音声が映像に対して遅れることであり、 音ずれの問題を発生させる。
しかも、lame.exeではデフォルトでLAMEタグを使用し、かつ、DirectShowフィルターのMP3デコーダーは一般に — 今回の実験した範囲では全てが — LAMEタグ非対応なので、 結果として、lame.exeをデフォルト設定で使った動画を再生すると、 高確率で、音声と映像が1フレームずつずれているというやや深刻な事態となる。
このことは、カラオケ字幕のような非常に精密なタイミング制御を行うとき、経験的に知られており、 2005年の「動画音声のlame: -tを付けないと音ずれ」ではLAMEタグが問題の核心であること、-tスイッチでLAMEタグを抑止すると問題が改善されることが指摘しされている。
予想されていた問題点の第一は、LAMEタグを使うと音ずれが大きくなること、 問題点の第二は、LAMEタグを使うと再生タイミングがデコーダー依存になり、エンコード時に正確な制御できなくなることだ。
今回の実験では、 上記のような経験的事実を、再現可能な観測事実としてはっきりさせるため、 LAMEタグを持つ動画をDirectShow経由で再生したときの音声タイミングがどうなっているのか、 WavDestを使って、0.1msの精度まで測定した。
結果として、第一の問題点は、観測的にも確認できた。 一方、経験に反して、第二の問題点は、観測的には確認できなかった。 すなわち、LAMEタグを含む場合のデコーダーの違いによるタイミングの違いは、この実験では検出できなかった。 経験上「mp3libよりlibmadの方がLAMEタグで音ずれしやすい」という予想があったが、 予想に反して、mp3libでもlibmadでも完全に同じに結果となった。 (予期に反すると言っても、-t推奨説に疑問を投げるものではなく、 逆に「予想していた以上に-tの必要性は高い」ということになる。)
主観的に目視等で経験していることと、データ上の結果が一致しない以上、 「同じDirectShow経由でもデコーダーの違いによって、 LAMEタグによるタイミングの違いがあるか?」の問(経験上はYes、実験結果はNo)については、 結論を保留しなければならない。
一方、 LAMEタグが音ずれを発生させること自体は、経験・実験・理論のすべてが一致し、 まず間違いない。
結論として、動画用の音声でLAMEを使う場合の-tスイッチの使用については、適切で望ましい選択であり、 強く推奨するが、上記のように(本筋とは関係ない部分とはいえ)未解明の点も残った。 この-t推奨はあくまで動画音声用のLAMEの場合限定で、 通常の単体のMP3を作る場合には関係ない。
冒頭に無音部を持つサンプルWAVファイルをもとに、
lame.exe 3.97 beta2 を使って、
lame --preset cbr 160 [-t] in.wav out.mp3
として、LAMEタグの有無以外は等しい二つのMP3ファイルを作成し、
VDMにて、同じ映像と二重化してAVIに格納した。
次に、GraphEdit 9.4.78上で、2種のAVIから分離されたMP3音声トラックを、 MP3デコーダー→WavDest(2006年3月20日版)経由でWAVファイル出力した(下のPNG画像参照)。 このとき、LAMEタグを含むAVIについては、複数のMP3デコーダーを試し、出力されるWAVファイルの違いを調べた。 テストしたのは、ffdshow 2006年3月30日版のmp3libとlibmad、IISのVer.1.5 Build 50であり、 デコーダーによって全体のサンプル数などに差が生じたものの、 音の出だしのタイミングには差がなかった。
各WAVファイルについて、オーディオエディタを使い、音が始まるタイミング(言い換えれば、冒頭の無音の長さ)を、 0.1ms単位まで調べた。
サンプルWAVでは、688.9msに音が鳴り始める。 これをLAMEタグありで、MP3化し、foobar2000でWAVにデコードすると、 音の出だしは688.8msとなった。 プリエコーによる歪みで計測上0.1msの差が出たものの(プリエコーそのものは音の出だしに含めていない)、 理論上、LAMEタグ対応プレーヤーでは、サンプル・アキュレートになるようだ。 一方、LAMEタグなしで同じ実験をすると、foobar2000での音の出だしは700.8msであり、 LAMEタグを使った場合より、少なくとも100倍のオーダーで不正確になることが分かる。
このように、LAMEタグは、再生側が対応してさえいれば、優れたものなのである。
一方、WavDestを使って、DirectShow内を流れるLAMEタグ付きMP3ストリームをWAVにデコードしてダンプさせたところ、 音の出だしが735.8msとなっており(デコーダーの違いによる差は検出できなかった)、 46.9msの音ずれが生じていた。23.976fpsの画像1フレームは41.7msであるから、 映像のまるまる1フレーム以上ずれてしまうのである。
LAMEタグなしのMP3について同様に調べると、開始点は711.8msであり、 誤差は22.9msに半減した。 このサンプル周波数では、LAMEタグを使わない限り、24msのずれは原理的に避けられない。 24ms以内に納まったということは、離散化誤差以外の余計な誤差は生じていないことを示唆する。 一方、LAMEタグを使った場合の誤差46.9msは、上記22.9msよりずっと大きく、ちょうど24ms誤差が増えていることが分かる。 LAMEタグがオーディオの1フレームを水増ししているためと考えれば、理屈に合う。
以上の結果は「動画音声のlame: -tを付けないと音ずれ」での検討とも、ほぼ一致している。
48000HzのWAVをMP3圧縮した場合、
実験的な試みであるが、-tスイッチを使い、かつ離散化誤差の分をあらかじめWAV側で補正しておくことなどで、 離散化誤差が生じた状態でタイミングが正確になるようなアプローチが考えられる。 例えば、-tなしで開始点が20ms遅れる場合、冒頭の無音を20ms削ったWAVを-tなしで圧縮すると、タイミングが正確になるのではないか。 映像の1フレームより短いタイミング差にこだわる必要があるのか自体も問題だが、 上記のアプローチは今後の研究課題だ。
離散化誤差について考えるとき、 「観測者とスピーカーの距離が約34cm離れるごとに、音速によっても1ms音ずれする」という事実にも注意しなければならない。 理論上正確に同期していても、画面・音源から離れていると、10ms程度の音ずれがある。
他方、経験的に、人間の視神経と聴覚神経・言語認識は反応速度が異なり、 物理的に正確に同期しているA/Vタイミングが、主観的に「正しいタイミング」と感じられないことがある。