トップ 検索 一覧 差分 ソース ヘルプ RSS ログイン

x264(sliced-threads,slices,slice-max-mbs,slice-max-size)

このページの全ては誤っているかもしれません。x264関連の記事に関してを読んでください。

x264(sliced-threads,slices,slice-max-mbs,slice-max-size)

タイトルはオプションの説明であるかの様になっているが、例によって好き勝手に書く。今回はマルチスライスとは何かという感じの漠然とした説明を試みる。

x264のr1242でマルチスライスのサポートが復活した。伝聞で申し訳ないが、Blu-ray関係ではマルチスライスが必須という話があるらしく、その対応らしい。

また、r1364ではsliced-threads(スライス毎にスレッドを割り当てるマルチスレッド方式)が復活した。圧縮率は悪化するものの、ゼロ遅延エンコードが可能で、規格が意図する並列処理方式だ。この記事は本来、sliced-threadsが主眼ではなく、slices等の方が主眼だが、便宜上この記事のタイトルに含めた。

 特徴

メリットは、Blu-rayやその他のスライスを必要とする規格・機器での再生を目的とした場合、再生互換性を高められるかも知れないことだ。また、再生機器によっては再生負荷が軽減すると思われる。ただし、上記のDoom9のスレッドによれば、特にマルチスライスを使用しなくても再生できている場合が多数で、しかもマルチスライスを使用していない既存のBDも多いらしい。つまり、あまり大きなメリットではない。

デメリットは、一般的なエンコード上のアドバンテージが殆どなく、むしろ性能劣化することだ。RD比(Rate- Distortion Rate:レート対歪み率、つまりデータサイズと画質の比率)やエンコード速度は基本的に悪化する。もしかしたら、PC上での再生負荷はデコーダによっては軽くなるかもしれないが、それならCAVLCや--no-weightbの方がよいのではないかと思う。

 使用上の注意点

一応、少しだけオプションとしての注意点を説明。

  • slices
    • slicesで指定した場合にはスライスが矩形になり、BDの仕様を満たす。
    • 最大値は…
      • interlacedの場合は高さを32で割った値。
      • 非interlacedの場合は高さを16で割った値。
      • いずれも小数点以下は切り上げで、上限を超えると最大値に切り捨てられる。
    • 適正値は、Blu-rayでは4スライスが必須という話がある(参考:[[|x264-changelog-jp r1400-r1499]]のr1480)。
    • 多すぎると後述のようにH.264規格への適合性が危ぶまれる。
  • slice-max-size/slice-max-mbs
    • 両者共にinterlacedとの併用は不可。
      • interlaced指定時はslice-max-size=0、slice-max-mbs=0になる。
    • slice-max-sizeとslice-max-mbsのどちらかを指定するとslicesは0になる。

 マルチスライスとは

以下、基本的にまるも大先生の過去の解説をベースにしており、分かる人はそちらを読むだけで分かるだろう。

よく1枚の画を表すのに「フレーム」や「ピクチャ」という言葉が使用されるが、H.264ではその1枚の画を「スライス」という単位に分割できることになっている。例えば画面の上半分と下半分、と言ったように。これにより、並列処理(≒マルチスレッド処理:ハードウェア実装ではモジュールやプロセッサ単位かもしれないがここではスレッドで統一する)の実装が多少楽になる。

H.264はフレーム間、ひいてはマクロブロック間の参照関係が複雑になっているので、元々並列処理が行いにくい規格だ。各フレームに1つのスレッドを割り当てて処理できれば簡単なのだが、先に「参照される」フレームが処理されていなければ「参照する」側のフレームを処理できない。すると、フレーム単位でスレッドを割り当てても、待ち状態で動作できないスレッドが存在することになる。そこでフレーム単位ではなく、例えば上半分と下半分という画面の領域ごとにスレッドを与え、それぞれの領域が独立に参照関係を解決しながらエンコード・デコードしていけば、待ち状態をなくすことができるというのが、画面領域=スライスの発想だ。

ピーク処理性能が低かったり、複雑な処理を行えない実装(廉価なハードやDSP・ASICなど)であっても、並列化すれば安価にH.264のコーデックが実現可能で、同じ設計で対応解像度のスケーラビリティが持たせられる(並列数を増減すればよい)点が重要なのだろう。

ちなみに、スライスは矩形(四角形)であるとは限らない。例えば320x240のフレームではMB(16x16)単位で言うと20行x15列=300個のMBマトリックスであるが、このうち2行+10個=50個のMBをスライス1、残りの12行+10個=250個のMBをスライス2とするような変則的な分割も可能で、slice-max-mbsを使用した場合にはこういう変則的スライスになるのだろう。

 デメリット

一見、それなりに意味のある機能のように思えるが、代償が大きい。

RD的な問題

画面を分割して別個にエンコードを行うと言うことは、同一フレーム内であってもそのスライスを跨る参照、つまり動き補償が行えない。このため、Iスライスの割合が上がり、P/Bスライスでもスライス境界付近はiのマクロブロックが多数発生したり、動き検索のヒット率が下がったりすると思われる。

サイズの問題

各スライスは個別にデコードできなければならない(依存関係があってはならない)のでCABACのコンテキストが共有できない。つまり各々のスライスは1からエンコードするため、圧縮効率が低下する。これも痛い。

これは圧縮理論上の原理(性質)によるものだが、説明するよりも、体感した方がわかりやすいだろう。7-zip(.7z)などのソリッド圧縮をサポートする汎用の圧縮形式で、多数のファイルをソリッドあり・なしで圧縮し比較してみればよい。例えばx264r1206のソースコードを7-zipの標準圧縮レベルで圧縮すると、302KB(ソリッドあり=分割しない)対408KB(ソリッド無し=分割する)で30%以上もサイズが増える。

スライスの数はソースコードのファイル数より遙かに少ないのでこの例ほどの影響はないだろうが、よほど特殊な例を除き単純に圧縮率が下がることはほぼ間違いない

処理効率の問題

先に「並列処理が多少楽」と書いたのはあくまで複雑な処理が苦手なハードウェアなどの実装が楽という話で、複雑な処理でも比較的楽に実装可能なソフトウェアでは事情が違う。

先のまるも大先生の解説によれば、x264は賢く、必要部分のエンコードが終わればそこを参照するフレーム(スライス)のエンコードスレッドを開始できるようになっているとのこと。PCではプロセッサ(CPU)の数以上に処理主体(スレッド)を割り当てることが可能で、スレッド間の処理時間の割り振りは柔軟に行われる。このため、PCでは待ち状態のスレッドが発生しても必ずしもプロセッサを余らせることにはならない。実際に待ち状態のスレッドが発生する条件はIDRの間隔(keyintやscenecut)や参照関係の設定(refやbframesやb-pyramid等)によるが、x264の自動的なスレッド数(プロセッサ数の1.5倍)は十分にプロセッサの処理能力を活かしていると思う。

そもそも、スライスによる並列処理の簡素化は、デブロックのせいで片手落ちになっている。デブロックはマクロブロック境界にかけるものだが、当然スライス境界にもかけなければ、スライス境界がブロックノイズならぬスライスノイズを発生してしまう。しかしスライス境界にデブロックをかけるためには両スライスが処理済みである必要があり、いずれにしてもここで同期処理は必要だ。そしてそれらのフレームを参照する際にも、H.264はインループフィルタなので、デブロック処理が完了するのを待たなければならない。つまり、スライスを採用してもスライス同士は本当の意味で独立ではなく、並列処理は一応可能だが、効率はよくない

(2010/04/24追記)H.264にはスライス境界にのみデブロックをかけない、という選択肢があるにはある。x264はr1546からsliced threadsでその方式(disable_deblocking_filter_idc=2)を使用するようになった。x264-changelog-jp r1500-r1599を見よ。これによって処理効率が上がり高速化したようだが、同時に、上記のスライスノイズが発生するようになったと思われる。

マルチスライス使用時にはデブロックをOFFとするのであれば効率は低下しないが、マルチスライスを定めるのであればVC-1のようにアウトループフィルタにすべきだったのではないかと思う。アウトループフィルタでは参照関係・動き補償関連処理がデブロックに依存しないため、より処理モジュール間の独立性が高まる。結果として同期が不要になり、並列処理が容易になる。

規格適合性の不安

Doom9のp4x4の規格適合性に関してのスレッドでakupenguin氏がマルチスライスの問題について言及している。H.264の規格書にはSliceRateという値があるが、akupenguin氏はこれが何を表すものなのか知りもしないので、x264が将来マルチスライスを再実装した場合には規格に適合しないかも、ということを述べている。

規格書を少し見てみた限りでは、スライスの最大数を制限するための係数であり、SliceRateが大きければ最大スライス数が小さく、SliceRateが小さければ最大スライス数が大きくなる。雰囲気としては、スライスが持つべき最低マクロブロック数のような意味になりそうだ。

SliceRateの値はMain/Highプロファイルでは22〜60(Level3以上で規定)で、通常スライス数は1桁程度にするだろうからほぼ問題ないように見える。が、若干不安だ。

 まとめ

規格上どうしても必要な場合を除けば、ほぼ使用するメリットがない。akupenguin氏が上記Doom9のスレッドでやる気がないと言っているのも分かる気がする。

 余談

本筋とは離れるが、調べていたときに思っていたことをメモ。

まるも大先生の解説のフォロー(?)

まるも大先生の解説では、

欠点は、シングルパスでのレートコントロールが事実上不可能になること。

とある。

筆者の理解ではマルチスライスだからレートコントロールができるものとも思えず、この意図がいまいち掴み切れていない。もしかしたらr607のchangelogにある

It is no longer possible to re-encode a frame

のこと(フレームを再エンコードできなくなった)を指しているのかも知れない。

これに関しては、r1213のVBVの修正(rc-lookahead)でかなり改善されて、r1272では単一フレームでのVBVもサポートされているので、現在ではあまり当てはまらないのではないかと思う。

マルチスライス対応の経緯

x264は以前にもマルチスライスをサポートしていて、一度r607で廃止された。これは、x264も当初は規格の意図に従ってマルチスライスでマルチスレッドの対応を行っていたが、その効率の悪さに開発者が辟易し、処理効率もRDも向上する方式にマルチスレッド対応を変更したものと思われる。

この流れからは何となく、当初のマルチスライス対応はそれ自体よりもマルチスレッド対応が重要だったのだろうと受け取れる。コミットは2006/12/15で、折しもCore2がノートPCにも浸透してきた頃。前述のまるも大先生の解説も、スレッドの解説であって本来はスライスの解説ではない。

以前はサポートしていたものであるから、今回の修正も酷く大きなものではない。大分以前からサポートは可能(パッチが存在していた)であったようだが、様々な意図があってコミットされずにいたようだ。

以前のマルチスライス対応は最大4スライスまでであったが、今回の対応では前述のように自由度が増している。

最終更新時間:2010年04月09日 03時29分23秒