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


関連記事

vuex-module-decoratorsとTypeScriptでvuexをスマートに書く

1 はじめに2 導入3 どのように記述するか3.1 初めに3.2 state3.3 mutation3.4 action3.5 getter3.6 async MutationAction3.7 Dy ...

react-icon

[React初心者]カスタムフックについて学ぶ

1 はじめに2 Ract Hook(フック)とは3 カスタムフックの実装3.1 フックのルール3.2 カスタムフック3.3 カスタムフックの実装4 さいごに5 おすすめ書籍 はじめに 今回はReact ...

[React]MUIのコンポーネントを使用したUI作成(Button、Alert編)

1 はじめに2 MUI3 Button3.1 Buttonの実装3.2 Buttonの使い分け3.2.1 不可逆な操作など、より強調したい時の使い方4 Alert4.1 Alertの実装4.2 Ale ...

Vue.js入門その1〜基本文法〜

はじめに 軽量JSフレームワークとして有名なVue.js。 最近、Laravelに触れる機会が増えたことと、以前からRails + Vueという構築を耳にするので、今更ではありますが勉強を始めようと思 ...

[Next.js]FirestoreのデータをServer Componentから取得する

1 はじめに2 Next.jsでFirestoreからデータを取得する方法2.1 Client Componentで直接Firestoreから取得2.2 Route Handlerを使ってAPI化し、 ...

フォロー

blog-page_side_responsive

2024年4月
 123456
78910111213
14151617181920
21222324252627
282930  

アプリ情報

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