0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Anime4K (4.0.1) を WebGL へ移植した話

Posted at

はじめに

動画プレイヤーを作ったので、今度は HTML の Video をいじってみたい!
その中で、手頃で便利な処理といえば、アプコン (アップコンバート) ですね!
というわけで、アニメで顕著な効果が出るといわれている Anime4K を使ってみたい!

でも、探したはいいものの 4系 (4.0.1) の WebGL 移植が見当たらない!
3系の昔の実装はありましたが、4系 に関しては全然見当たりません...

じゃあ、やってしまえということで、Anime4K 4系 (4.0.1) を WebGL に移植した!
という記事になります。

成果物

Anime4K.js という形で作りました。
静止画、動画のアップコンバートをサポートしています。

読み込むと、こんな感じで window に Anime4KJS が生えて、アップスケーラを作れます。
現時点では video の信号の 2倍 アップスケールができます。

const upscaler = new Anime4KJS.VideoUpscaler(30 /* TARGET FPS */, Anime4KJS.ANIME4KJS_SIMPLE_M_2X /* PROFILE */);
upscaler.attachVideo(videoElement, canvasElement);
upscaler.start(); // start upscaling
// ...
upscaler.stop(); // stop upscaling

この辺の敵

浮動小数点数テクスチャ

Anime4K は CNN の演算結果を、そのままテクスチャに入れ、次の層へ伝搬していきます。
このため、テクスチャが小数に対応していないと、切り捨てが発生し丸められます。
その結果として、整数で処理を行うと、層が進むたびに切り捨てられてしまいます。

なので、浮動小数点数テクスチャを使って、整数への丸めを回避する必要がありました。

WebGL1 の場合

WebGL1 で浮動小数点数テスクチャを扱う場合には、以下の拡張を使う必要があります。

  • OES_texture_float: 32bit 精度の浮動小数点数テスクチャ
  • OES_texture_half_float: 16bit 精度の浮動小数点数テスクチャ

OES_texture_float 拡張を使う場合には、このようにデータを書き込みます。

gl.getExtension('OES_texture_float'); // 1度やればいい, get で有効化って微妙じゃない?
// 実際にデータを入れるときに gl.FLOAT を指定する
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.FLOAT, null);

OES_texture_half_float の場合は、以下のようになります。
拡張のオブジェクトの中の HALF_FLOAT_OES を使うと半精度 (16bit) になります。

const ext = gl.getExtension("OES_texture_half_float");
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,  width, height, 0, gl.RGBA, ext.HALF_FLOAT_OES, null);

WebGL2 の場合

WebGL2 では、浮動小数点テスクチャはサポートされています。
ただ描画する際には EXT_color_buffer_float 拡張が必要です。

gl.getExtension('EXT_color_buffer_float'); // 1度やればいい, get で有効化って微妙じゃない?

// 32bit float
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA32F, width, height, 0, gl.RGBA, gl.FLOAT, null);
// 16bit float
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, width, height, 0, gl.RGBA, gl.HALF_FLOAT, null);

MPV のフック形式の自動変換

Anime4K は MPV のフック形式 でフラグメントシェーダーを記述しています。
これは、勝手に頂点シェーダーやシェーダーの変数定義を行ってくれる便利なものです。
また、フックタイミングを記載でき、様々な処理に割り込んでシェーダーを適用できます。

ただ、WebGL に移植する際には、この機能を自前で補完しなければなりません。
シェーダーの量が多いため、ここは自動で TypeScript + glsl に変換するコードを書きました。

基本的に Anime4K 4系 (4.0.1) は、以下のフックで構成されています。
(昔は YUV に対するフックなどがありましたが、4系では見当たりませんでした)

  • MAIN フック: YUV から RGB に変換された後で、リサイズ前
  • PREKERNEL フック 最終出力前

この部分を TypeScript + WebGL でフック処理するように変換しています。

課題

処理の最適化

オリジナルは 4ms でアップスケールできるようなのですが、14ms くらいかかってしまいます。
なぜか 1 テスクチャ書き込みに 1ms かかってしまうみたいです。
テスクチャを 12 個くらい書いてるので、14 ms かかってしまっているという感じです。

最適化が足りてないのだろうと思っているので、今後改善したいところです。

まとめ

Anime4K 4系 (4.0.1) を WebGL に移植して、ブラウザでアップコンバートしました。
浮動小数点数テクスチャ や MPV (libplacebo) のフックを勉強するいい機会になりました。

こんどは、アニメ向けではないアップスケーラも挑戦してみたいところです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?