« 可逆圧縮コーデック「Lagarith」の設定や仕様、使い方等について | トップページ | 初期ディレイカットしたMP4をニコニコ動画にアップロードした場合の問題点 »

2010年4月 4日 (日)

x264の初期ディレイカット機能の概要(あってるか自信なし)

ふとしたきっかけで初期ディレイについて調べ始めたのですが色々ややこしい・・・。
とりあえずここでは、Seraphy氏の拡張x264出力(GUI)にあった
   「初期ディレイカット機能」
について、自分なりにまとめてみようと思います。

※注意
  筆者はx264やMP4の仕様などさっぱりわかっていませんし参考書等も読んでいません。
  「タイムコード?なにそれ?おいしいの?」とか、その程度のレベルです。
  ググった記事だけをもとに考え、「多分こんな感じかなあ(゚∀゚)」という程度で
  すっげえアバウトにまとめていますので、鵜呑みにして信じ込むと大変危険です。
  なるべくソース元の情報などをしっかり読み、各自で判断してください。
  用語の使い方も、かなり曖昧だと思いますし、間違ってる部分もあるかもしれません。
  間違いがあったら指摘していただけると幸いです。
  (知識が貧弱なので指摘されても理解できないという可能性もありますが・・・)

x264のエンコードで利用される仕組みの1つとして「Bフレーム」があります。
エンコード時にBフレームを使う設定(--bframesを0より大きくする)にすると、デコードの際に遅延が発生します。
Bフレームを使うだけで合計1フレーム分の遅延が発生し、Bフレームのピラミッド参照化(--b-pyramid)も使うと
合計2フレーム分の遅延が発生します。

これはバグではなく、Bフレームの仕組みに由来するものです。
Bフレームをデコードするためにはその前に参照するIフレームやPフレームをデコードする必要があり、
Bフレームのピラミッド参照化を行なった場合は更に参照Bフレームのデコードまで必要になるので、
その分の遅延が発生します。これを「(Bフレーム由来の)初期ディレイ」と呼んでいます。

初期ディレイが発生する仕組みを図に書いてみました。
といっても、まるもさんのDiaryの図をほぼそのままパクってますが・・・。   

  Delay

 
ちゃんとした解説などは以下の参考サイトなどを参照して下さい。
ただしAVIについての話はMP4とはちょっと違うところもあるので注意。

 参考サイト:
    まるもさんのDiary 2007-10-11 x264 [22] --b-pyramid
    b_pyramid - MPlayer and MEncoder on MacOSX
    MPEG-4のB- frameを AVI/VFW に入れるハッキング - MPlayer and MEncoder on MacOSX

ピラミッド参照化(-b-pyramid)を使った場合、合計2フレーム分の遅延なので、
30fpsの映像ならば、
  1[秒]÷30[フレーム/秒]×2[フレーム]=0.0666[秒]
の初期ディレイが発生します。この程度ならあまり気にならないかもしれませんが、
1fpsの映像ならば、
  1[秒]÷1[フレーム/秒]×2[フレーム]=2[秒]
の初期ディレイが発生します。
つまり、fpsの値が小さいほど遅延が認識されやすくなり、影響は大きくなるといえるでしょう。

さて、次にMP4ファイルを再生することを考えてみます。

まずはWMPやMPC-HCなど、DirectShowを利用したプレーヤーで再生するケース。
この場合、MP4に対応したスプリッター(DirectShowフィルタ)が必要になります。
主なフリーのMP4スプリッターとしては、
  Haali Media Splitter (現時点の最新は2010/3/27版)
  MPC-HC(Gabest)のMP4 Splitter (現時点の正式リリースはMPC-HC1.3.1249.0)
  Nero MP4 Splitter (使ったことがないのでよく知らない)
があります。
再生時の初期ディレイの扱いは、スプリッターによって異なるようです。

 ■Haali Media Splitter
    →2009/12/19版までは初期ディレイを自動的に補正(カット)していた。
    →2010/3/27版では初期ディレイの自動補正は行なわないようになった。
      (正確には初期ディレイの補正方法が変わったというか扱いが変わった)

 ■MPC-HC(Gabest)のMP4 Splitter
    →MPC-HC 1.3.1249.0では、初期ディレイは補正せずそのまま扱う。

 ■Nero MP4 Splitter
    →初期ディレイを自動的に補正する。

また、Flash PlayerはDirectShowを用いず独自の再生処理を行ないますが、
初期ディレイについては何も補正せず、そのまま扱うようです。
つまりMPC-HCのMP4 Splitterと似たような見え方になります。

さて、MP4コンテナには、一般的に映像と音声が入っているわけですが、
初期ディレイは映像で発生するものであり、音声は関係なくそのまま再生されます。
つまり、再生環境によって、以下のように見え方が変わってくるということになります。

  Case1.映像の初期ディレイを自動的に補正する環境の場合
       →音声と映像はちゃんと意図したタイミングで同期されて再生される

  Case2.映像の初期ディレイが補正されない環境の場合
       →映像が音よりも初期ディレイ分遅れて見えることになる。
        「音ずれ」と言うよりも「映像ずれ」という感じの状態。

   ※実際には音声にもエンコードディレイやデコードディレイがあり、
     例えばwavをneroAacEncでエンコードすると冒頭部に無音部分が追加される。
     そのため映像と音声がどれだけずれるかは映像と音声のディレイを
     総合的に考えないといけないということになるが、
     とりあえずここでは映像の初期ディレイのみを考えることにする。

このように再生環境によって見え方が違うのは好ましくないということで、
なるべく再生環境に依存せずに、MP4コンテナの仕様の範囲で、
Bフレーム由来の初期ディレイを解消する方法が検討され、
この結果作られたのが、Seraphy氏の拡張x264出力(GUI)のr1376まで存在した、
  「初期ディレイカット(DTS Compression)」
という機能のようです。

この初期ディレイカットという機能は、MP4コンテナの
  DTS(Decoding Time Stamp)
  CTS(Composition Time Stamp)
という仕組みを利用したもののようです。
DTSやCTSについては以下のVFR maniac氏の記事がとてもわかりやすいと思います。
ちなみにVFR maniac氏は、x264開発者の1人です。

  delayとB-Pictures 変態≠Hentai

初期ディレイカットの処理内容についてググったところ、以下のような書き込みも見つかりました。

  x264 VFW 専用スレ Part2 レス711
  「MP4を再生するほとんどの環境では合成時刻(CTS)=表示時刻となっていますから、
   CTSを0から始まるようにすることでディレイをカットします。
   このとき、コンテナの仕様としては各ピクチャのCTS以前の時刻を
   デコード時刻(DTS)にする必要があるので、たとえばIフレームが表示されている
   時間内(33ミリ秒くらい)にPフレームをデコードするようにDTSを書き換えているようです。
   そうすることで、スプリッタがHaaliでもGabestでも、PSPやPS3で再生しても
   同じ結果になるようにしているようです。」

  VFR maniac氏がプログラムを公開していたeSnipsの過去キャッシュ
  「seraphy氏や私が行ってる初期ディレイカットは#x264devではDTS compressionと呼んでいる。
   最初のいくつかのフレームのDTSを二番目に表示されるフレームのCTSより小さくするためだ。
   CFRでは実際,一つのフレームが持つ表示期間より短くなる。なのでcompression=圧縮。」

また、この処理を実現するにあたり、DTSの重複を防ぐために、
Timescaleを4倍の精度にして処理を行なっているようです。
(4倍にすることで、元のスケールの1/4刻みでの時間指定が可能になる)

大雑把に言うと、拡張x264出力(GUI)の初期ディレイカット機能というのは、
以下のような機能なんじゃないかなあと。

  「Bフレームのデコードに必要なフレーム(Pフレームとか参照Bフレームとか)を、
   遅延を考慮して早めにデコードするようにDTSを書き換えることにより、
   Bフレームを時間どおりに表示させる。
   CTSもゼロから始まるように書き換えるので、スプリッターが持つ
   初期ディレイ補正機能(※1)は働かなくなり、指定したDTSとCTSに基づく動作になるので、
   ほとんどの再生環境で同じような見え方(初期ディレイが発生しない)になる。」

   ※1・・・スプリッターの初期ディレイ補正処理の詳細はよくわかりませんが、
        多分CTSの値、もしくはCTSとDTSの差(CTSOffsetと呼ぶらしい)を見て
        行なってるのだと推測しました。
        「CTSが0から始まらないってことはBフレーム遅延があるんだな!」と判断して
        その補正を行なうとかそんな感じじゃないだろか。
        こちらのレスを見ると、Haali氏は「ctts correction」と表現している模様。
        また、こちらのレスのedts処理の説明に
          「MP4出力においてBフレーム使用時(正確には最初のCTSOffsetが正の時)に
           edtsを書き込む仕様に変更しました」
        とあるので、これと同じような判定なのかなあと推測しました。
        あくまでも貧弱な知識からの推測なんで、間違ってるかもしれません。

ちょっくらイメージ図を書いてみました。

  Delaycut

しかし、Seraphy氏の拡張x264出力(GUI)のr1400からは、初期ディレイカット機能は削除されました。
これは、本家 x264 の r1379 にて、
  「MP4出力の際は、edtsを用いて初期ディレイを打ち消すための調整を行なう」
という仕様変更が発生したためのようです。

これにともなって、いくつかの問題も発生していますが、そのへんはまた別エントリで書きたいと思います。

なお、この初期ディレイカット機能は、ニコニコ動画とは相性が悪いようです。
これについては
  「初期ディレイカットしたMP4をニコニコ動画にアップロードした場合の問題点
でまとめてみました。

|

« 可逆圧縮コーデック「Lagarith」の設定や仕様、使い方等について | トップページ | 初期ディレイカットしたMP4をニコニコ動画にアップロードした場合の問題点 »

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/1278146/34081433

この記事へのトラックバック一覧です: x264の初期ディレイカット機能の概要(あってるか自信なし):

« 可逆圧縮コーデック「Lagarith」の設定や仕様、使い方等について | トップページ | 初期ディレイカットしたMP4をニコニコ動画にアップロードした場合の問題点 »