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


関連記事

もうすぐ登場!Vue 3の変更点まとめ

1 はじめに2 仕様変更2.1 複数のv-modelが定義可能に2.2 template直下に複数のタグを記述可能に2.3 開始処理がcreateAppに2.4 scoped cssの仕様変更2.5 ...

react-icon

Vite 3を使ってみた

1 はじめに2 なぜViteは早いのか2.1 Native ESMの活用2.2 esbuildによる事前バンドル3 Viteのセットアップ3.1 Reactテンプレートでのセットアップ3.2 vite ...

Vue.js入門その2〜Vueインスタンスってなんぞ?〜

1 はじめに2 Vueインスタンス3 プロパティとメソッド4 インスタンスライフサイクルフック5 フィルター6 算出プロパティ6.1 例文6.2 算出プロパティを使用した書き換え6.2.1 HTML6 ...

tailwindcss

Tailwind CSSの基礎とVue.jsへの導入

1 はじめに2 Tailwind CSSとは2.1 utility class3 Bootstrapとの比較3.1 柔軟性3.2 コード量3.3 学習コスト3.4 ファイルサイズ3.5 その他4 なぜ ...

Vue.js入門その3〜簡単にTODOアプリを作ってみたよ〜

はじめに 7/12 修正 記事下部にて、filterメソッドを使用している箇所がありましたが、forEachの方が適しているとご指摘がありましたので、修正しました。 以前Qiitaの方に投稿した記事で ...

フォロー

blog-page_side_responsive

2024年4月
 123456
78910111213
14151617181920
21222324252627
282930  

アプリ情報

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