Get to know MDN better
このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docs コミュニティーについてもっと知り、仲間になるにはこちらから。
このガイドでは、WebCodecs API の基本的な使用方法について解説します。これには、動画や音声のエンコードおよびデコードの方法に加え、VideoFrame および AudioData の使用方法も含まれます。
VideoEncoder の基本的な使用パターンは、インスタンス化から始まります。この際、output および error コールバック関数を定義します。output コールバックは、EncodedVideoChunk と metadata を引数として受け取ります。metadata は EncodedVideoChunkMetadata 辞書であり、オプションの decoderConfig プロパティを含みます。このメタデータは、動画ファイルへの多重化を行う際に、多重化ライブラリーによって必要とされます。
次に、コーデックパラメーターや、幅、高さ、ビットレート、フレームレートなどのその他のエンコードパラメーターを設定して、エンコーダーを構成する必要があります。コーデックの選択方法については、コーデックの選択ガイドを参照してください。
次に、VideoFrame オブジェクトのエンコードを開始します。この際、エンコード対象の VideoFrame を指定するだけでなく、そのフレームをキーフレームとしてエンコードするかどうかを示す keyFrame パラメーターも指定します。
最初にエンコードするフレームはキーフレームにする必要があります。VideoEncoder では、明示的に指定しなくても最初のフレームが自動的にキーフレームとして扱われますが、明示的に設定しておくことをお勧めします。一般的なキーフレームの間隔は、30 フレームごとまたは 60 フレームごとです。キーフレームの数を増やすと動画ファイルのサイズが大きくなりますが、逆に減らしすぎると、一部の動画プレーヤーで再生が不安定になる場合があります。
メモリーリークを防ぐため、VideoFrame オブジェクトはエンコード用に送信したらすぐに閉じることが重要です。VideoFrame オブジェクトはサイズが大きいため、メモリー内にアクティブなフレームが 100 個未満であっても、アプリケーションがクラッシュする可能性があります。
なお、VideoEncoder には encodeQueue と呼ばれる、エンコード待ちのフレームのキューも用意されています。30 fps でアニメーションをレンダリングしている場合、各レンダリングごとに encoder.encode(frame) を実行すると、エンコーダーの処理能力が 10 fps しかない場合、エンコーダーのキューは次第に膨れ上がり、最終的に動画メモリーが不足してプロセスがクラッシュしてしまいます。
したがって、レンダリングループ内で VideoEncoder.encodeQueueSize を確認し、そのサイズが無制限に増大しないように注意しながら、エンコーダーへのフレーム送信方法とタイミングを適切に管理する必要があります。
dequeue イベントを使用することで、エンコードキューが縮小したタイミングを検知できるため、encodeQueueSize をポーリングする必要がなくなります。
エンコード用のすべてのフレームの送信が完了したら、flush() メソッドを呼び出す必要があります。
端末やブラウザーによっては、flush() が呼び出されるまで、エンコーダーが最後の数個の EncodedVideoChunk オブジェクトを返さない場合があります。VideoEncoder の使用を完全に終了したら、システムリソースを解放するために close() メソッドを呼び出す必要があります。
VideoEncoder は、ユーザーがタブを切り替えてブラウザがリソースを解放した場合など、さまざまな理由でエンコード処理中にエラーをスローすることがあります。エラーが発生すると、エンコーダーは "closed" 状態に永久に移行します。閉じたエンコーダーを再設定することはできず、新しい VideoEncoder インスタンスを作成する必要があります。新しいエンコーダーによってエンコードされる最初のフレームは、キーフレームでなければなりません。
同様に、動画のデコードを行う場合も、まず output および error コールバック関数を指定して VideoDecoder をインスタンス化します。ここで、output コールバックはデコーダーから返される VideoFrame オブジェクトを受け取ります。
次に、デコーダーの設定を行う必要があります。動画ファイルをデコードする場合、多重分離ライブラリーが適切なデコーダー設定を提供してくれます(多重化と多重分離を参照してください)。WebCodecs の送信側と受信側間で動画をストリーミングする場合、デコーダーの設定は、エンコードされたチャンクを生成した VideoEncoder が返すメタデータと同一になります。
動画ファイルをデコードする場合、動画チャンクを抽出するために多重分離ライブラリーが必要になります。その後、それらのチャンクをデコード処理に送信します。ただし、1つのチャンクだけをデコードに送信し、フレームが出力されるのを待ってから次のチャンクを送信するようなことは避けてください。ブラウザや端末、動画そのものの仕様によっては、デコーダーがフレームの返却を開始する前に複数のチャンクを送信する必要がある場合があり、必要なチャンクの最小数は端末によって異なります。
VideoEncoder と同様に、VideoDecoder も管理が必要なデコードキューを保持しています。一度に数千個のチャンクを VideoDecoder に送信すると、デコーダーが終了したり失敗したりする可能性があるため、アプリケーション側で VideoDecoder.decodeQueueSize が無制限に増加しないようにする必要があります。エンコーダーと同様に、dequeue イベントを待ち受けしてデコードキューの管理に役立てることもできます。
デコード用のすべてのフレームの送信が完了したら、flush を実行できます。
端末やブラウザーによっては、flush() が呼び出されるまで、デコーダが最後の数個の VideoFrame オブジェクトを返さない場合があります。VideoDecoder の使用を完全に終了したら、システムリソースを解放するために close() メソッドを呼び出す必要があります。
VideoDecoder は、ソースの EncodedVideoChunk 内のデータが破損している、あるいは欠落しているなど、さまざまな理由でデコード中にエラーを発生させる可能性があります。デコーダーが失敗すると、そのデコーダーは恒久的に "closed" 状態に移行するため、新しい VideoDecoder インスタンスを作成する必要があります。新しいデコーダーによって最初にデコードされるチャンクはキーフレームでなければならないため、処理を再開する前に、現在の位置から次のキーフレームまで早送りする必要があります。
VideoFrame は、ピクセルデータやタイムスタンプなどのメタデータを含む、単一の非圧縮動画フレームを表します。これは、エンコードされた動画をデコードする際に VideoDecoder によって返されるほか、さまざまなソース画像から生成されることもあります。
VideoFrameは、任意の画像ソースから作成できます。タイムスタンプはマイクロ秒単位であることに注意してください。
動画編集アプリケーションでは、通常、Canvas から VideoFrame を生成することで動画をエンコードします。この場合、ソース動画や画像はキャンバスコンテキスト内で使用され、エフェクトや座標変換が適用されます。また、Canvas はユーザーがプレビューできるだけでなく、エンコードされる VideoFrame の画像ソースとしても使用されます。
ArrayBuffer などのバイナリーデータから直接 VideoFrame を作成することも可能です。ただし、その場合は format とメタデータを指定する必要があり、フレームの構築に使用するデータが指定された形式に準拠していることを確認する必要があります。
VideoFrame オブジェクトは、グラフィックメモリー上のデータと紐付けられています。Canvas、Bitmap、Video、Image のいずれかから VideoFrame を作成する場合、データはグラフィックメモリーからグラフィックメモリーへコピーされるため、比較的効率的です。
バイナリデータ(例:ArrayBuffer や Uint8ClampedArray)から構築された VideoFrame では、CPU からグラフィックメモリーへのコピー処理が発生します。この処理が繰り返し行われると、パフォーマンスの低下を招く可能性があります。
最後に、前述の動画のデコードのセクションで示したように、VideoDecoderを使用してEncodedVideoChunkオブジェクトをデコードすることで、VideoFrameオブジェクトを生成することもできます。
デコードされた動画は、VideoFrame オブジェクトを Canvas へレンダリングすることで、ブラウザー上でも再生可能です。レンダリング方法によってパフォーマンス特性が異なるため、計算負荷の高い動画処理を実行する際には、この点が重要になる場合があります。
drawImage メソッドを使用すると、CanvasRenderingContext2D に図形を描画できます。
2D キャンバスコンテキストはシンプルかつ柔軟な API を備えていますが、ブラウザーごとに内部の実装が異なるため、ブラウザー間で動作にばらつきが生じ、一般的にパフォーマンスが低下しています。
フレームから ImageBitmap を作成し、transferFromImageBitmap メソッドを使用してキャンバスにレンダリングすることで、ImageBitmapRenderingContext 経由でフレームをキャンバスにレンダリングすることも可能です。
この手法では、グラフィックメモリー内にフレームのコピーを 1 つ作成します。これにより、Canvas2D API に比べてブラウザー間での動作の一貫性が高まり、全体的にパフォーマンスも向上する一方で、比較的シンプルな実装が可能です。
VideoFrame をキャンバスにレンダリングする最も効率的な方法は、WebGPU の importExternalTexture メソッドを使用することです。
importExternalTexture は、WebGPU パイプライン内でメモリー上のまったく同じ VideoFrame オブジェクトを使用するため、ゼロコピー操作となり、効率的です。これは VideoFrame をレンダリングする上で最もパフォーマンスが高い方法ですが、設定が最も複雑でもあります。
VideoFrame オブジェクトは大量の GPU メモリーを消費する可能性がある上、動画処理では 1 秒あたり多数のフレームを処理するため、アプリケーションのクラッシュを防ぐためには、メモリー管理に細心の注意を払い、メモリーリークを回避する必要があります。
何よりもまず、フレームは不要になった時点で明示的に解放する必要があります。
エンコードを行う際は、エンコード用にフレームを送信したらすぐにそのフレームを閉じることができます。
また、レンダリング直後にフレームを閉じるようにしてください。
スレッド間(例:ワーカー)で VideoFrame を転送する際は、移譲可能オブジェクトとして転送する必要があります。
WebCodecs は、AudioEncoder および AudioDecoder を通じて、Opus および AAC コーデックを使用した音声のエンコードとデコードに対応しています。音声を扱う前に、注意すべき重要な点がいくつかあります。
WebCodecs とウェブオーディオ API の間には直接的な橋渡しはありません。AudioData オブジェクトは、生の音声データを表現するために AudioBuffer を使用するウェブオーディオ API に直接渡すことはできません。
再生を行う際の推奨される方法は、多重化ライブラリーを使用して EncodedAudioChunk オブジェクトをメモリー内のバッファーに多重化し、そのバッファーを AudioContext.decodeAudioData() を通じてデコードすることです。
あるいは、copyTo() を使って AudioData から生のサンプルを抽出し、手動で AudioBuffer を構築することもできますが、この方法ではチャンクごとに CPU 側でのデータコピーが必要となるため、処理速度が低下します。
音声エンコードは動画エンコードよりも単純です。キーフレームもなければ、ハードウェアアクセラレーションに関する懸念もなく、それぞれの AudioData は正確に 1 つの EncodedAudioChunk を生成します。エンコーダーは、単純な非同期パイプラインとして扱うことができます。
Opus と AAC のどちらを選ぶかについては、コーデックの選択のガイドを参照してください。
オーディオのデコードは、エンコードと同じ手順で行われます。デコーダーの設定は、通常、開発者が選択するのではなく、多重分離ライブラリーによって提供されます。
AudioData オブジェクトは、通常 0.2 ~ 0.5 秒分の生の音声セグメントを表します。生のサンプルは、AudioData.copyTo() メソッドを使用して Float32Array データとして抽出されます。抽出パターンは、AudioData オブジェクトの format プロパティによって異なります。
最も一般的な形式は f32-planar で、各チャンネルが別々のプレーンに格納されます。planeIndex を使用すると、各チャンネルを個別にコピーできます。
あまり一般的ではない f32 形式では、すべてのチャンネルが単一の配列([L, R, L, R, ...])にインターリーブされて格納されます。この場合、インターリーブされたバッファー全体をコピーし、手動でインターリーブ解除を行ってください。
両方の形式に対応するには、次のようにします。
生のサンプルから AudioData を構築するには、すべてのチャンネルのデータを 1 つの Float32Array に連結し、各チャンネルのサンプルを順番に配置(f32-planar レイアウトに準拠)するとともに、numberOfFrames をチャンネルごとのサンプル数に設定する必要があります:
特定の AAC コーデック文字列(mp4a.40.5、mp4a.40.05、mp4a.40.29)は、スペクトル帯域複製 (SBR) と呼ばれる技術を使用する設定に対応しており、これによりデコーダーは、デコーダー設定で指定されたサンプリングレートの 2 倍のレートで音声を出力することになります。設定値と一致すると仮定するのではなく、常に audioData.sampleRate を直接読み取るようにしてください。 VideoFrame と同様に、AudioData オブジェクトはメモリーを解放するために明示的に閉じる必要があります。
AudioData は VideoFrame に比べてはるかに少ないメモリーしか必要としませんが、生の音声データはかなりのメモリーを消費します。48kHz のステレオ音声を 1 時間分保存すると、約 1.4GB になります。ファイルサイズが大きい場合は、音声データを一度にすべて処理するのではなく、バッチ処理でデコードおよび処理を行うべきです。
より良いインターネットのための青写真。
このコンテンツの一部は、©1998–2026 個人の mozilla.org 協力者です。コンテンツはクリエイティブ・コモンズ・ライセンスのもとで利用できます。