Saturday, November 13, 2010

[x264] Disable Duplication in Weighted Prediction for P-frames [patch]

ここ数日weightp関連のコードをずっと眺めていました。
それで一つパッチを書きましたので、こっそり公開。
おそらくある程度の需要はあると思うし、自分も今後使っていくつもりです。
ただこのパッチ、#x264devにおいてDark_Shikari氏にrejectされたパッチです。
(というかrejectされてコミットされないから自分のブログで公開してるんですけどね…w)
有用性と危険性をきちんと理解した上で自己責任で使用してください。

patch -> here

ことの発端はこの記事
Leopardのときは本当に意味不明な挙動で何が原因かサッパリわからなかったのですが、
SnowLeopardにOSを更新してからやっと不具合の出る原因にパターンが見え始めました。
(OSと一緒にQuickTime Player のバージョンも上がっています)
どうやらx264でエンコードするときに
--ref 15 & --weightp 2 または --ref 16 & --weightp 1 または --ref 16 & --weightp 2
のいずれかを指定するときちんとデコードできない動画ができあがるらしい。
(つまり ref + weightp > 16 のときにデコードがおかしくなる)

それでweightp関連のコードを読み始めたんですが、encoder/encoder.c:1418の
int x264_weighted_reference_duplicate( x264_t *h, int i_ref, const x264_weight_t *w )
以下処理が絡んでいるみたいなんですね。

それでこの処理を丸々無効にするオプション"--no-weightp-dup"を作ってみました。
そのパッチがこれ
パッチを覗いてもらえればわかると思いますけど、実装方法は至ってシンプルです。


まず、このパッチの有用性は何かと言うと、

  1. weightpを使った動画だとデコードがぶっ壊れたデコーダでもデコード可能になる
    (例えばCoreAVCのバージョン1系、FlashPlayerのバージョン10.0系など)
  2. refに制限があるハードを対象にしたエンコードにおいてweightpの選択肢が増える
    (例えばPlayStation Portableなど)
  3. weightpを使用しないよりはフェードが改善する
    (Duplicationを行なった場合ほどではないですが)
  4. weightpを使用したエンコードにおいてエンコード速度上がる
    (特に --weightp 2 の場合はDuplicationありに比べて速度向上が大きいです)

おそらく一番大きな影響は1番目ですかね。
知人の協力も得て、古いCoreAVCとFlashPlayerで再生可能なことを確認しています。
Dark_Shikari氏のこの記事で批判されている一連のデコーダですね…(笑)
次に2番目の件ですが、例えばPSPにおいてはこのような報告が出ていますが、
(どうやら、PSPは ref + weightp > 3 になると駄目みたい)
このパッチを使うと--ref 3 & --weightp 2 などのエンコードができるようになるはずです。
PSP持ってないのでこちらは確認できていないですが、たぶん大丈夫だと思います(笑)
3番目と4番目の説明は略。
興味がある方はご自分でエンコードして確認してみてください。
エンコードされた動画をバイナリエディタやMediaInfoで見てみると、
今までweightp=2などと書き込まれていた部分が、weightp=2:1などになっているはずです。
Duplicationが有効だと:1が付き、無効だと:0が付きます。


次に、このパッチが蹴られた理由は何かと言うと、

  1. デコードが壊れるのが嫌なら--weightp 0 を使えばいい
    (実際に人達はそうしている)
  2. Duplicationを使う方がフェードの質が上がる
    (そもそも質を上げるためにこんな処理をしている)
  3. 不正確な実装のデコーダを助長してしまう
    (不正確な実装のデコーダでもデコードできてしまうので)

以上がコミットされない大きな理由です。
他にもk-means(--weightp 3として実装予定かつ実装未定のもの)でDuplicationが有用とか、
mbaffとの関わりでとか、いろいろ理由があるらしいです。
そんなこんなで、"I reject this patch on principle"と言われました(笑)


ですが。
個人的には--weightp 0よりは --no-weightp-dup & --weightp > 0 の方が質は上がってると思うし、
PSP用エンコは現状 --ref 1 & --weightp 2 か --ref 2 & --weightp 1 しかweightpの選択肢がないし、
k-meansはいつ実装されるかサッパリだし(肝心のdylan氏が行方不明)、
mbaffとか自分にとっては関係ないし…。
などの理由で今後も使うことにしました。
デフォルトではDuplicationをきちんと行いますし、現状ではそこまで悪影響はないかと。
今後公開していくバイナリでもこのパッチを当てていくつもりです。
もし今後weightpの実装が変わり、このパッチがcriticalな影響を及ぼす危険があったら、
そのときはすぐに使用を止めればいいだけかなと。



例えばニコニコ動画など、限られたビットレートで画質を維持しないといけない上に
FlashPlayerを全員が最新にしているとは限らない、という場で結構使えるんじゃないかな。
他には、CoreAVCで見たいけどバージョン更新するお金がない人とか…?
あと、Blu-ray Disc用エンコードでは現在 --weightp 0 が推奨となっているらしいですが、
もしかしたらこのパッチでweightpが使えるようになるかもしれないとかそうじゃないとか。
まあどの層に需要があるかはまだハッキリしませんが、役に立てたらうれしいです(笑)



なお、今回の件でも普段からお世話になっている方々にテストなどでお世話になりました。
Special thanks for boiled_sugar, Chikuzen, and  JEEB.

No comments:

Post a Comment