FrontEnd

フロントエンドで動画デコレーション&レンダリング

投稿日:

はじめに

今回は、以下のように動画用の背景画像をHTML+CSSで作り、その中心に動画を合成してレンダリングしてみたいと思います。 今回主に紹介したいのは、「DOMのキャプチャ」と「ffmpeg.wasm」を使ったレンダリングです。

レンダリング方法の検討

次の2つの方法を考えました。

  1. 背景用のDOMをキャプチャし、ffmpegで動画と合成する
  2. DOM上で背景とvideoタグを配置した上で、を丸ごと全フレームを画像に変換し、ffmpegまたはWebCodecsで動画にエンコードする

今回は1の方法で実装を進めます。2もやってみたのですが、次のような理由で実装が難しく、断念しました。

  • キャプチャ対象のDOMにvideoタグが含まれると、iOSでキャプチャできない。そのため、別途Remotion Player外にvideoタグを用意し、キャプチャするときだけRemotion Player内のVideoコンポーネントの代わりにcanvasを置き、外のvideoタグの内容をcanvasに書き写す必要がある。
  • Playerを1フレーム進めてから、実際に動画のフレームが描画されるまでラグがあり、videoの onSeeked でキャプチャする必要があるが、それを1フレームずつ繰り返していると途中で止まってしまう。

ちなみに、1の方法だと、動画の最中で背景に変化をさせることができません。

背景部分のキャプチャ

まずは、背景部分をキャプチャします。

modern-screenshotの導入

DOMをキャプチャするパッケージはいくつかありますが、その中でも最も様々なDOMやデバイスに対応していると思われる「modern-screenshot」を使います。このハッケージはhtml-to-imageのフォークです。(ちなみに、html-to-imageもdom-to-imageのフォークですが、dom-to-imageはメンテナンスが止まっています。)
これらのパッケージの動作原理ですが、こちらが参考になります。基本的には、 <svg> タグ内にHTMLを埋め込むことができる <foreignObject> の中にHTMLを入れ、svgをPNGに変換することで画像化しています。

それでは、moden-screenshotをpnpmで導入します。

DOMのキャプチャ

modern-screenshotの domToPng() を使ってキャプチャします。この関数はPromiseを返すのですが、

これで、DOMをキャプチャすることができました。

ffmpeg.wasmで画像と動画を合成

ffmpegでエンコード

最後に、ffmpeg.wasmで、先ほどキャプチャした画像と動画を合成していきます。

-filter_complexでは、背景画像の上に、動画を中心にフィットするように配置しています。。動画をフィットして配置するコマンドは以下を参考にしました。
http://sogohiroaki.sblo.jp/article/183618558.html

また -preset ultrafast にすることで、エンコード速度を最速にしています。これは、ffmpeg.wasmはトランスコード(動画や音声などののデコード・エンコード)のパフォーマンスが悪く、presetを指定しないとエンコードにめちゃくちゃ時間が時間がかかってしまうためです。
presetのみを指定すると、速度を速くすればするほどファイルサイズが大きくなります(ビットレート一定モードと併用すると、時間をかけた分品質が向上します)。このオプションの詳細は以下が参考になります。
https://tech.ckme.co.jp/ffmpeg_h264.shtml

これで実際に動かしてみると、以下のような動画が出力されました!

Next.jsでの動的import

ここまでの実装で、一通り動くのですが、Next.jsを使っていると以下のエラーがNext.jsのログに出力されます。

Node.jsではffmpeg.wasmは使えないようなので、どうやらサーバサイドレンダリング時にffmpeg.wasmを使っているのが良くないようです。そこで、ffmpegを使っているコンポーネントそのものをdynamic importすることで、サーバサイドレンダリングを回避してみます。

dynamic() の第2引数に { ssr: false } を指定することで、サーバサイドレンダリングをしないようにできます。このようにすることで、先ほどのエラーを回避することができます。

さいごに

フロントエンドだけでなんとか動画の合成とエンコードに成功しました!

おすすめ書籍

Reactハンズオンラーニング 第2版 ―Webアプリケーション開発のベストプラクティス プログラミングTypeScript ―スケールするJavaScriptアプリケーション開発

blog-page_footer_336




blog-page_footer_336




-FrontEnd
-

執筆者:

免責事項

このブログは、記事上部に記載のある投稿日時点の一般的な情報を提供するものであり、投資等の勧誘・法的・税務上の助言を提供するものではありません。仮想通貨の投資・損益計算は複雑であり、個々の取引状況や法律の変更によって異なる可能性があります。ブログに記載された情報は参考程度のものであり、特定の状況に基づいた行動の決定には専門家の助言を求めることをお勧めします。当ブログの情報に基づいた行動に関連して生じた損失やリスクについて、筆者は責任を負いかねます。最新の法律や税務情報を確認し、必要に応じて専門家に相談することをお勧めします。


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


関連記事

docker-syncでファイルの同期を高速化する

1 はじめに2 docker-syncの導入3 設定ファイルの作成3.1 docker-composer.yml3.2 docker-compose-dev.yml3.3 docker-sync.ym ...

js

JSで緯度経度情報から住所を取得する

1 はじめに2 キーを取得する2.1 キーを取得する3 コード4 参考5 さいごに はじめに Google Maps JavaScript APIを利用して、緯度経度の数値から住所を検索する方法を紹介 ...

react-icon

React Konvaで状態管理されたCanvasを描画してみた

1 はじめに2 Canvasとは?3 React Konvaとは4 着せ替えアプリっぽいサンプルを作成4.1 React Konvaの導入4.2 画像の描画4.3 stateによるCanvas描画4. ...

Vue on Rails で作ったアプリを振り返ってみる

1 はじめに2 全体的なこと2.1 ディレクトリ構成2.2 CSSフレームワーク2.3 Capistranoでのデプロイ3 axiosのラッパー4 Vuex4.1 ログインの状態管理5 Router6 ...

Vuexの機能と使い方

1 はじめに2 Vuexとは2.1 Single Source of Truth2.2 状態の取得、更新のカプセル化2.3 単方向データフロー3 Vuexのストア3.1 ステート3.2 ゲッター3.3 ...

フォロー

blog-page_side_responsive

2024年4月
 123456
78910111213
14151617181920
21222324252627
282930  

アプリ情報

私たちは無料アプリもリリースしています、ぜひご覧ください。 下記のアイコンから無料でダウンロードできます。