H.263からSparkへのトランスコーディング(下)


こんにちは、稲垣@CEREVOです。

H.263からSorenson Sparkへの変換、前回は文法をチェックしてビットストリームの変換処理を実現するところまでを扱いました。しかし、Inter Pictureは崩れてしまってまともにデコードできませんでした。一体なぜでしょうか?

Motion Vectorの変換

こういうときはデコード結果をよく観察してみるものです。すると、Motion Vectorがおかしくなったような動きをしていることに気づきました。また、全体が崩れるのではなく、最初のGOBだけは正しく再生できているように見えました。実際、avidemux2でMotion Vectorを表示させると、最初のGOBのMotion Vectorだけは正しくデコードされているようでした。

ここでH.263のデコード仕様を眺めてみると、Motion Vectorに関してpredictという単語が目にとまります。つまり、MBに符号化されているのはMotion Vectorそのものではなく、周囲のMotion Vectorを元にして予測したMotion Vectorからの残差だったのです。そういう予測からの残差を符号化する手法はADPCMなどでも使われますが、だからMVD (Motion Vector Data) などいうワケの分からない名前が付いていたわけですね。この予測はGOB内で完結するようになっていて、したがってGOB境界が変わると予測結果が変わってしまいます。GOBヘッダが無いというのは、こういう意味の変化も伴うわけです。一部のヘッダが違うだけというのは、誤解でした。

ですから、MVDを正しく変換するためには、デコードしてからエンコードしなおさなければなりません。つまり、H.263の仕様に従って予測したMotion VectorにMVDを加算してMotion Vectoreを得、今度はSparkの仕様に従って予測したMotion Vectorをそれから減算してMVDに戻すわけです。処理自体は大したものではありません。Motion Vectorのバッファを一行分使えばできます。

なお、H.263エンコーダがUMV (Unlimited Motion Vecotr) 拡張を使ったエンコーダだったら変換はできないところでしたが、今回使っていたH.263エンコーダは何の拡張オプションも持っていない簡単なものなので、完全に変換することが可能でした。つまりMotion Vectorは64通り、MVDも64通りの値を取るので、変換することでデータの長さは増減するものの、可逆的に変換できるのです (ちなみにSparkはUMVが標準装備です)。

変換の完成

こうしてH.263からSorenson Sparkへのビットストリームトランスコーダは完成しました。要点をおさらいしましょう。

まずH.263エンコーダの設定ですが、GOB境界でQuantizerが大きく変化しないようにしなければなりません。Quantizer指定のVBRモードなどを使わざるを得ません。

次にトランスコーダは、おおむね以下のようなものになるでしょう:

  • Pictureヘッダを変換し、GOBヘッダを削除する。必要ならGOB境界でのQuantizerの変化をMBにエンコードする (実装しませんでしたが)
  • バイト単位でのコピーなどという手抜きはできず、ビットストリームをきちんとパースしなければならない
  • Motion Vectorを再エンコードする

さらなる変換

H.263ではいわゆるCIF系の11:9のアスペクト比しか使えないのですが、Sparkでは任意のアスペクト比を使うことができます。当然、4:3や16:9といった普通のアスペクト比で出力したくなります。我々はすでにトランスコーダを作ったので、Pictureヘッダを書き換え、MBを途中で打ち切ることは容易ですが、注意すべき点が二つあります。Motion Vectorが画面外にはみ出しているときのことと、MBがはみ出しているときのことを考えなければなりません。

まず、Motion Vectorのはみ出しは、SparkがUMVをサポートしているので問題ありません。これが逆変換だったら確実に問題になるところでした。

MBが画面外にはみ出ているとき、H.263では、境界の部分のピクセルがずっと続いているものとして扱うことになっています。ですから、たとえばCIFより小さい画像をエンコードするときは、境界のピクセルをコピーしてCIFの画面を埋めてからエンコードします。こうすると、(結果的に) 画面外を参照するような動きベクトルがあっても正しくデコードできるようになるはずです。実際は、エンコーダーが見ている画像とデコーダが見ている画像でノイズの有無が生じるので齟齬が起き、切った端からノイズが出たりしますが……

結局、一点だけ注意しておけば、画像を好きなアスペクト比に叩き切ることができます。簡単なのは下だけを切り捨てることで、実際に実装したのはここまでです。

まとめ

このような技術が、CEREVO CAM live!やLIVEBOX、LiveShellには搭載されています。

なんというか、変換できてよかったと思います。本当に。