トップ 検索 一覧 ヘルプ 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関係ではマルチスライスが必須という話|http://forum.doom9.org/showthread.php?t=142407]があるらしく、その対応らしい。

また、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になる。

!!マルチスライスとは

以下、基本的に[まるも大先生の過去の解説|http://www.marumo.ne.jp/db2007_7.htm#21]をベースにしており、分かる人はそちらを読むだけで分かるだろう。

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

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

!規格適合性の不安

Doom9の[p4x4の規格適合性に関してのスレッド|http://forum.doom9.org/showthread.php?t=125734]でakupenguin氏が[マルチスライスの問題|http://forum.doom9.org/showthread.php?p=1002803#post1002803]について言及している。
H.264の規格書には''SliceRate''という値があるが、akupenguin氏はこれが何を表すものなのか知りもしないので、x264が将来マルチスライスを再実装した場合には規格に適合しないかも、ということを述べている。

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

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

!!まとめ

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

!!余談

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

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

まるも大先生の解説では、
{{bq
欠点は、シングルパスでのレートコントロールが事実上不可能になること。
}}
とある。

筆者の理解ではマルチスライスだからレートコントロールができるものとも思えず、この意図がいまいち掴み切れていない。もしかしたらr607のchangelogにある
{{bq
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スライスまでであったが、今回の対応では前述のように自由度が増している。