控制相机平移、倾斜度和缩放

摄像头的平移、倾斜和缩放功能终于可以在网页上控制了。

François Beaufort
François Beaufort

会议室级视频会议解决方案部署了具有平移、倾斜和缩放 (PTZ) 功能的摄像头,以便软件将摄像头对准会议参与者。从 Chrome 87 开始,摄像头上的平移、倾斜和缩放功能可供使用 MediaDevices.getUserMedia()MediaStreamTrack.applyConstraints() 中的媒体轨道约束条件的网站使用。

使用此 API

功能检测

硬件功能检测与您可能习惯的方式不同。如果 navigator.mediaDevices.getSupportedConstraints() 中存在 "pan""tilt""zoom" 约束条件名称,则表示浏览器支持用于控制摄像头 PTZ 的 API,但不表示摄像头硬件是否支持该 API。从 Chrome 87 开始,桌面设备支持控制摄像头 PTZ,而 Android 设备仍仅支持缩放。

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

请求摄像头云台访问权限

只有在用户通过提示明确向摄像头授予 PTZ 权限的情况下,网站才能控制摄像头的 PTZ。

如需请求摄像头 PTZ 访问权限,请调用 navigator.mediaDevices.getUserMedia() 并提供 PTZ 约束条件,如下所示。这将提示用户同时向普通摄像头和具有 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 页面,然后查看“视频捕获”标签页中的“Pan-Tilt-Zoom”(平移-倾斜-缩放)列;“Pan-Tilt”(平移-倾斜)和“Zoom”(缩放)分别表示摄像头支持“PanTilt(绝对值)”和“Zoom(绝对值)”UVC 控件。基于 Chromium 的浏览器不支持“PanTilt(相对)”和“Zoom(相对)”UVC 控件。

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...
}

您还可以通过调用 navigator.mediaDevices.getUserMedia() 并使用某些相机 PTZ 理想约束值来配置相机平移、倾斜和缩放。如果您已提前知道摄像头的 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 BhaumikEero Häkkinen 在规范和实现方面的工作。 主打图片由 Unsplash 用户 Christina @ wocintechchat.com 提供。