Region Capture を使用したタブ共有の改善

François Beaufort
François Beaufort

このウェブ プラットフォームではすでに、ウェブアプリで現在のタブの動画トラックをキャプチャできます。このバージョンでは、これらの動画トラックを切り抜くメカニズムである Region Capture が搭載されています。ウェブアプリは現在のタブの一部を対象領域として指定し、ブラウザはその領域外のすべてのピクセルを切り抜きます。

これまでウェブアプリでは、動画トラックを「手動で切り抜くことができました」が、すべてのフレームを直接操作できました。これは堅牢でもパフォーマンスも高くありませんでした。リージョン キャプチャは、これらの欠点を解決します。これで、ウェブアプリはブラウザに代わって作業を行うように指示できます。

リージョン キャプチャについて

Dynamic ContentTM を使用してウェブサイトを作成できました。これは史上最高のウェブアプリです。人々はコラボレーションをし続けて使用するのを止められません。次のステップとして、仮想会議機能を埋め込むことも考えられます。あなたはそれを採用することにしました。あなたは既存のビデオ会議サービス プロバイダと提携し、ウェブアプリをクロスオリジンの iframe として埋め込むことにしました。ビデオ会議ウェブアプリは、現在のタブを動画トラックとしてキャプチャし、リモート参加者に送信します。

メイン コンテンツ領域とクロスオリジン iframe がハイライト表示されたウェブアプリを表示するブラウザ ウィンドウのスクリーンショット。
メイン コンテンツ領域は青色で、クロスオリジン iframe は赤色で表示されます。

ちょっと待ってください… ユーザー自身の動画をユーザーに送り返すわけにはいきませんよね。その部分は切り取ったほうがいいでしょう。これには、埋め込まれた iframe は、表示するコンテンツとその場所を認識できないため、何らかの支援なしに切り抜くことはできません。理論的には、目的の座標を渡すことができます。しかし、ユーザーがウィンドウのサイズを変更した場合はどうなるでしょうか。ビューポートをスクロールしますか?ズームインまたはズームアウトしますか?レイアウトが変更されるような方法でページを操作しますか?新しい座標をキャプチャ用 iframe に送信しても、タイミングの問題によってフレームが切り抜かれる場合があります。

では、一部をキャプチャする方法を使ってみましょう。ページに Element<div> の場合もあります)があり、メイン コンテンツが含まれています。これを mainContentArea とします。ビデオ会議ウェブアプリで、この要素の境界ボックスで定義された領域をリモートでキャプチャして共有します。mainContentArea から CropTarget を派生させます。この CropTarget をビデオ会議ウェブアプリに渡します。この CropTarget を使用して動画トラックを切り抜くと、そのトラックのフレームは mainContentArea の境界ボックス内にあるピクセルのみで構成されます。mainContentArea のサイズ、形状、位置を変更すると、どちらのウェブアプリからも追加の入力を必要とせずに、動画トラックがそれに沿って移動します。

これらの手順をもう一度確認しましょう。

ウェブアプリで CropTarget を定義するには、選択した要素を入力として CropTarget.fromElement() を呼び出します。

// In the main web app, associate mainContentArea with a new CropTarget
const mainContentArea = document.querySelector("#mainContentArea");
const cropTarget = await CropTarget.fromElement(mainContentArea);

CropTarget をビデオ会議ウェブアプリに渡します。

// Send the CropTarget to the video conferencing web app.
const iframe = document.querySelector("#videoConferenceIframe");
iframe.contentWindow.postMessage(cropTarget);

ビデオ会議ウェブアプリは、メインウェブアプリから受信した切り抜きターゲットを使用してセルフキャプチャ動画トラックで cropTo() を呼び出し、CropTarget で定義された領域にトラックを切り抜くようブラウザにリクエストします。

// In the embedded video conferencing web app, ask the user for permission
// to start capturing the current tab.
const stream = await navigator.mediaDevices.getDisplayMedia({
  preferCurrentTab: true,
});
const [track] = stream.getVideoTracks();

// Start cropping the self-capture video track using the CropTarget
// received over window.onmessage.
await track.cropTo(cropTarget);

// Enjoy! Transmit remotely the cropped video track with RTCPeerConnection.

これで完了です。これで完了です。

詳細

特徴検出

CropTarget.fromElement() がサポートされているかどうかを確認するには、次のコマンドを使用します。

if ("CropTarget" in self && "fromElement" in CropTarget) {
  // Deriving a target is supported.
}

CropTarget の導出

mainContentArea という要素に注目しましょう。そこから CropTarget を導出するには、CropTarget.fromElement(mainContentArea) を呼び出します。成功した場合、返された Promise は新しい CropTarget オブジェクトで解決されます。そうしないと、不当な数の CropTarget オブジェクトを作成した場合は拒否されます。

const mainContentArea = document.querySelector("#mainContentArea");
const cropTarget = await CropTarget.fromElement(mainContentArea);

Element とは異なり、CropTarget オブジェクトはシリアル化可能です。たとえば、Window.postMessage() を使用して別のドキュメントに渡すことができます。

切り抜き

タブキャプチャでは、動画トラックは MediaStreamTrack のサブクラスである BrowserCaptureMediaStreamTrack としてインスタンス化されます。このサブクラスは cropTo() を公開します。track.cropTo(cropTarget) を呼び出して、mainContentArea(cropTarget の派生要素)の輪郭に合わせて切り抜きを開始します。

成功すると、その後のすべての動画フレームが mainContentArea の境界ボックス内に収まるピクセルで構成されることが保証されると、Promise が解決されます。

失敗した場合、Promise は拒否されます。これは次のような場合に発生します。

  • CropTarget は別のタブに作成されました。(現時点では - 最新情報をお待ちください)。
  • CropTarget は、存在しない Element から派生しています。
  • トラックにクローンがある。(問題 1509418 を参照)。
  • 現在のトラックは自己撮影動画トラックではありません。下記をご覧ください。

cropTo() メソッドは、セルフキャプチャだけでなく、タブキャプチャの動画トラックでも公開されます。そのため、トラックを切り抜く前に、ユーザーが現在のタブを選択したかどうかを確認することをおすすめします。これは、キャプチャ ハンドルを使用して実現できます。preferCurrentTab を使用して、ユーザーにセルフキャプチャを促すようにブラウザに指示することもできます。

// Start cropping the self-capture video track using the CropTarget.
await track.cropTo(cropTarget);

切り抜かれていない状態に戻すには、null を指定して cropTo() を呼び出します。

// Stop cropping.
await track.cropTo(null);

遮蔽するコンテンツと遮蔽されるコンテンツ

リージョン キャプチャでは、z インデックスではなく、ターゲットの位置とサイズのみが重要です。ターゲットを覆っているピクセルはキャプチャされます。ターゲットの不完全な部分はキャプチャされません。

これは、領域キャプチャが基本的に切り抜きであるという帰結です。もう 1 つの代替 API(今後独自の API が追加される予定)は、要素レベルのキャプチャです。つまり、オクルージョンに関係なく、ターゲットに関連付けられたピクセルのみをキャプチャします。このような API では、単純な切り抜きとはセキュリティとプライバシーの要件が異なります。

領域キャプチャ API と要素レベルのキャプチャ API の異なる結果の画像。
遮蔽コンテンツがある場合の領域キャプチャの動作。

セキュリティとプライバシー

リージョン キャプチャを使用すると、タブ内のすべてのピクセルをすでに監視しているウェブアプリが、その一部のピクセルを自発的に削除できます。新しい情報を得ることができないため、明らかに安全です。

地域の捕捉を使用すると、リモート参加者に送信される情報を制限できます。たとえば、スピーカー ノートではなくスライドを共有したい場合、

スライドとスピーカー ノートが表示されているブラウザ ウィンドウのスクリーンショット。
スライドとスピーカー ノートが含まれるウェブアプリ。
ノートをリモートで共有することは非常に望ましくありません。キュー リージョン キャプチャ。

ローカルでは、リージョン キャプチャによってセキュリティが強化されることはありません。トラックを別のドキュメントに渡した場合も、受信側ドキュメントはトラックの切り抜きを元に戻し、キャプチャしたタブのすべてのピクセルにアクセスできます。

Chrome では、キャプチャされたタブの周囲に青い枠線が表示されます。切り抜かれた部分の周囲に青い枠線が描画されます。

デモ

リージョン キャプチャを試すには、Glitch でデモを実行します。ソースコードをチェックアウトしてください。

ブラウザ サポート

対応ブラウザ

  • Chrome: 104。
  • Edge: 104。
  • Firefox: サポートされていません。
  • Safari: サポートされていません。

地域キャプチャは、Chrome 104 のパソコンでのみご利用いただけます。

次のステップ

今後、ウェブでの画面共有を改善する予定の機能のプレビューをご紹介します。

  • リージョン キャプチャは、他のタブのキャプチャをサポートします。
  • 条件付きフォーカスを使用すると、キャプチャ ウェブアプリは、キャプチャされたディスプレイ サーフェスにフォーカスを切り替えるか、フォーカスの変更を回避するようブラウザに指示できます。
  • Element-level Capture API が提供されることがあります。

フィードバック

Chrome チームとウェブ標準コミュニティは、リージョン キャプチャに関する皆様のご意見をお待ちしております。

デザインについて教えてください

領域キャプチャが想定どおりに機能しない点はありますか?または、アイデアを実装するために必要なメソッドやプロパティが不足している場合は、セキュリティ モデルに関するご質問やご意見がございましたら、

  • GitHub リポジトリで仕様に関する問題を報告するか、既存の問題にコメントを追加してください。

実装に関する問題

Chrome の実装にバグが見つかりましたか?それとも、実装が仕様と異なるのでしょうか?

  • https://new.crbug.com でバグを報告します。できるだけ詳細な情報を含め、再現手順を簡単に記載してください。Glitch は、簡単な再現手順をすばやく共有するのに適しています。

クリエイターを応援する

リージョン キャプチャを使用する予定はありますか?皆様の公開サポートは、Chrome チームが機能の優先度を判断したり、他のブラウザ ベンダーにそれらのサポートがいかに重要であるかを示すのに役立ちます。

@ChromiumDev にツイートして、どこでどのように使用しているかをお知らせください。

謝辞

この記事をレビューしてくれた Joe Medley に感謝します。