カメラのパン、ティルト、ズームを制御する

カメラのパン、チルト、ズームが、ついにウェブで制御できるようになりました。

François Beaufort
François Beaufort

ルームスケールのビデオ会議ソリューションでは、パン、チルト、ズーム(PTZ)機能を備えたカメラを配置し、ソフトウェアでカメラを会議参加者に向けることができます。Chrome 87 以降、カメラのパン、チルト、ズーム機能は、MediaDevices.getUserMedia()MediaStreamTrack.applyConstraints() のメディア トラック制約を使用するウェブサイトで利用できるようになります。

API の使用

機能検出

ハードウェアの特徴検出は、これまで慣れ親しんできたものとは異なります。navigator.mediaDevices.getSupportedConstraints()"pan""tilt""zoom" の制約名がある場合、ブラウザはカメラの PTZ を制御する API をサポートしていますが、カメラ ハードウェアがサポートしているかどうかはサポートしていないことがわかります。Chrome 87 時点で、カメラの PTZ の操作はパソコンでサポートされていますが、Android では引き続きズームのみがサポートされています。

const supports = navigator.mediaDevices.getSupportedConstraints();
if (supports.pan && supports.tilt && supports.zoom) {
  // Browser supports camera PTZ.
}

カメラの PTZ アクセスをリクエストする

ウェブサイトがカメラの PTZ を操作できるのは、ユーザーがプロンプトからカメラに PTZ 権限を明示的に付与した場合のみです。

カメラ PTZ へのアクセスをリクエストするには、下記のように PTZ 制約を指定して navigator.mediaDevices.getUserMedia() を呼び出します。通常のカメラと PTZ カメラの両方の権限を付与するようユーザーに求めるメッセージが表示されます。

macOS 用 Chrome でのカメラの PTZ ユーザー プロンプトのスクリーンショット。
カメラの PTZ ユーザー プロンプト。

返される Promise は、カメラの動画ストリームをユーザーに表示するために使用される MediaStream オブジェクトで解決されます。カメラが PTZ をサポートしていない場合は、通常のカメラ プロンプトがユーザーに表示されます。

try {
  // User is prompted to grant both camera and PTZ access in a single call.
  // If camera doesn't support PTZ, it falls back to a regular camera prompt.
  const stream = await navigator.mediaDevices.getUserMedia({
    // Website asks to control camera PTZ as well without altering the
    // current pan, tilt, and zoom settings.
    video: { pan: true, tilt: true, zoom: true }
  });

  // Show camera video stream to user.
  document.querySelector("video").srcObject = stream;
} catch (error) {
  // User denies prompt or matching media is not available.
  console.log(error);
}

以前に付与されたカメラの権限(特に PTZ アクセス権のない権限)は、PTZ が利用可能になっても自動的に PTZ アクセス権を取得することはありません。これは、カメラ自体が PTZ をサポートしている場合でも同じです。権限はもう一度リクエストする必要があります。幸い、Permissions API を使用して、PTZ 権限のステータスをクエリしてモニタリングできます。

try {
  const panTiltZoomPermissionStatus = await navigator.permissions.query({
    name: "camera",
    panTiltZoom: true
  });

  if (panTiltZoomPermissionStatus.state == "granted") {
    // User has granted access to the website to control camera PTZ.
  }

  panTiltZoomPermissionStatus.addEventListener("change", () => {
    // User has changed PTZ permission status.
  });
} catch (error) {
  console.log(error);
}

Chromium ベースのブラウザがカメラの PTZ に対応しているかどうかを確認するには、内部の about://media-internals ページに移動し、[動画キャプチャ] タブの [パン / チルト / ズーム] 列を確認します。「パン / チルト」と「ズーム」は、カメラが「パン / チルト(絶対)」と「ズーム(絶対)」の UVC コントロールをサポートしていることを意味します。Chromium ベースのブラウザでは、「PanTilt(Relative)」と「Zoom(Relative)」の UVC コントロールはサポートされていません。

PTZ カメラのサポートをデバッグするための ChromeOS の内部ページのスクリーンショット。
PTZ カメラのサポートをデバッグするための内部ページ。

カメラの PTZ を操作する

先ほど取得した stream オブジェクトのプレビュー MediaStreamTrack を使用して、カメラの PTZ 機能と設定を操作します。MediaStreamTrack.getCapabilities() は、サポートされている機能と範囲または許容値を含む辞書を返します。対応して、MediaStreamTrack.getSettings() は現在の設定を返します。

パン、チルト、ズームの機能と設定は、カメラでサポートされており、ユーザーがカメラに PTZ 権限を付与している場合にのみ使用できます。

カメラの PTZ を操作する。

適切な PTZ 高度な制約を指定して videoTrack.applyConstraints() を呼び出し、次の例に示すようにカメラのパン、ティルト、ズームを制御します。成功すると、返された Promise は解決します。それ以外の場合は、次のいずれかの場合、拒否されます。

  • カメラに PTZ 権限が付与されていない。
  • カメラ ハードウェアが PTZ 制約をサポートしていない。
  • ページはユーザーには表示されません。Page Visibility API を使用して、ページの可視性の変化を検出します。
// Get video track capabilities and settings.
const [videoTrack] = stream.getVideoTracks();
const capabilities = videoTrack.getCapabilities();
const settings = videoTrack.getSettings();

// Let the user control the camera pan motion if the camera supports it
// and PTZ access is granted.
if ("pan" in settings) {
  const input = document.querySelector("input[type=range]");
  input.min = capabilities.pan.min;
  input.max = capabilities.pan.max;
  input.step = capabilities.pan.step;
  input.value = settings.pan;

  input.addEventListener("input", async () => {
    await videoTrack.applyConstraints({ advanced: [{ pan: input.value }] });
  });
}

if ("tilt" in settings) {
  // similar for tilt...
}
if ("zoom" in settings) {
  // similar for zoom...
}

カメラの PTZ の理想的な制約値を指定して navigator.mediaDevices.getUserMedia() を呼び出すことで、カメラのパン、チルト、ズームを構成することもできます。これは、カメラの PTZ 機能が事前にわかっている場合に便利です。必須の制約(最小値、最大値、正確な値)は使用できません。

const stream = await navigator.mediaDevices.getUserMedia({
  // Website asks to reset known camera pan.
  video: { pan: 0, deviceId: { exact: "myCameraDeviceId" } }
});

遊び場

Glitch でデモを実行して、API を試すことができます。ソースコードを確認してください。

セキュリティに関する考慮事項

仕様作成者は、ユーザー コントロール、透明性、人間工学などのコアを使用して、この API を設計して実装しました。この API の使用は、主に Media Capture and Streams API と同じ権限モデルによって制限されます。ユーザー プロンプトに応じて、ページがユーザーに表示されている場合にのみ、ウェブサイトでカメラ PTZ を制御できる。

ブラウザの互換性

MediaStream API

対応ブラウザ

  • Chrome: 55.
  • Edge: 12.
  • Firefox: 15.
  • Safari: 11.

ソース

Permissions API

対応ブラウザ

  • Chrome: 43.
  • Edge: 79.
  • Firefox: 46。
  • Safari: 16。

ソース

Page Visibility API

対応ブラウザ

  • Chrome: 33.
  • Edge: 12.
  • Firefox: 18.
  • Safari: 7

ソース

MediaDevices.getUserMedia()

対応ブラウザ

  • Chrome: 53.
  • Edge: 12。
  • Firefox: 36.
  • Safari: 11.

ソース

MediaDevices.getSupportedConstraints()

対応ブラウザ

  • Chrome: 53.
  • Edge: 12.
  • Firefox: 44。
  • Safari: 11.

ソース

MediaStreamTrack.applyConstraints()

対応ブラウザ

  • Chrome: 59.
  • Edge: 12.
  • Firefox: 43.
  • Safari: 11.

ソース

MediaStreamTrack.getCapabilities()

対応ブラウザ

  • Chrome: 59.
  • Edge: 12.
  • Firefox: 132.
  • Safari: 11.

ソース

MediaStreamTrack.getSettings()

対応ブラウザ

  • Chrome: 59.
  • Edge: 12。
  • Firefox: 50。
  • Safari: 11.

ソース

関連情報

謝辞

この記事は、Joe MedleyThomas Steiner が確認しました。仕様と実装に携わっていただいた Intel の Rijubrata Bhaumik 氏と Eero Häkkinen 氏に感謝いたします。UnsplashChristina @ wocintechchat.com によるヒーロー画像。