Cómo controlar el desplazamiento lateral, la inclinación y el zoom de la cámara

Por fin, las funciones de desplazamiento lateral, inclinación y zoom de las cámaras se pueden controlar en la Web.

François Beaufort
François Beaufort

Las soluciones de videoconferencias de sala implementan cámaras con capacidades de panorámica, inclinación y zoom (PTZ) para que el software pueda apuntar la cámara a los participantes de la reunión. A partir de Chrome 87, las funciones de panorámica, inclinación y zoom de las cámaras están disponibles para los sitios web que usan restricciones de segmentos de contenido multimedia en MediaDevices.getUserMedia() y MediaStreamTrack.applyConstraints().

Cómo usar la API

Detección de atributos

La detección de funciones para el hardware es diferente de lo que probablemente estés acostumbrado. La presencia de los nombres de restricciones "pan", "tilt" y "zoom" en navigator.mediaDevices.getSupportedConstraints() indica que el navegador admite la API para controlar la PTZ de la cámara, pero no si el hardware de la cámara la admite. A partir de Chrome 87, se admite el control de la cámara PTZ en computadoras de escritorio, mientras que Android solo admite el zoom.

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

Cómo solicitar acceso a la PTZ de la cámara

Un sitio web solo puede controlar la PTZ de la cámara si el usuario le otorgó permiso de PTZ de forma explícita a través de un mensaje.

Para solicitar acceso a la PTZ de la cámara, llama a navigator.mediaDevices.getUserMedia() con las restricciones de PTZ como se muestra a continuación. Esto le pedirá al usuario que otorgue permisos PTZ a la cámara normal y a la cámara.

Captura de pantalla de un mensaje para el usuario de una cámara PTZ en Chrome para macOS.
Mensaje para el usuario de la cámara PTZ.

La promesa que se muestra se resolverá con un objeto MediaStream que se usa para mostrarle al usuario la transmisión de video de la cámara. Si la cámara no admite PTZ, el usuario recibirá un mensaje de cámara normal.

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);
}

Un permiso de cámara otorgado con anterioridad, específicamente uno sin acceso a PTZ, no obtiene acceso a PTZ automáticamente si está disponible. Esto es así incluso cuando la cámara admite PTZ. Se debe volver a solicitar el permiso. Afortunadamente, puedes usar la API de Permissions para consultar y supervisar el estado del permiso de 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);
}

Para saber si un navegador basado en Chromium admite PTZ para una cámara, ve a la página interna about://media-internals y consulta la columna "Pan-Tilt-Zoom" en la pestaña "Video Capture". "Pan tilt" y "zoom" significan, respectivamente, que la cámara admite los controles UVC "PanTilt (Absolute)" y "Zoom (Absolute)". Los controles UVC "PanTilt (Relative)" y "Zoom (Relative)" no son compatibles con los navegadores basados en Chromium.

Captura de pantalla de la página interna de ChromeOS para depurar la compatibilidad con cámaras PTZ.
Página interna para depurar la compatibilidad con la cámara PTZ

Cómo controlar la cámara PTZ

Manipula las capacidades y la configuración de la PTZ de la cámara con la vista previa MediaStreamTrack del objeto stream que se obtuvo antes. MediaStreamTrack.getCapabilities() muestra un diccionario con las capacidades compatibles y los rangos o valores permitidos. En consecuencia, MediaStreamTrack.getSettings() muestra la configuración actual.

Las funciones y la configuración de paneo, inclinación y zoom solo están disponibles si la cámara las admite y el usuario le otorgó permiso de PTZ.

Controla la cámara PTZ.

Llama a videoTrack.applyConstraints() con las restricciones avanzadas de PTZ adecuadas para controlar el desplazamiento lateral, la inclinación y el zoom de la cámara, como se muestra en el siguiente ejemplo. La promesa que se muestra se resolverá si se ejecuta de forma correcta. De lo contrario, se rechazará en los siguientes casos:

  • no se otorga el permiso de PTZ a la cámara.
  • El hardware de la cámara no admite la restricción de PTZ.
  • la página no es visible para el usuario. Usa la API de visibilidad de páginas para detectar cambios en la visibilidad de la página.
// 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...
}

También es posible configurar el desplazamiento lateral, la inclinación y el zoom de la cámara llamando a navigator.mediaDevices.getUserMedia() con algunos valores de restricción ideales de PTZ de la cámara. Esto es útil cuando se conocen las capacidades de PTZ de la cámara con anticipación. Ten en cuenta que aquí no se permiten las restricciones obligatorias (mín., máx., exactas).

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

Área de juegos

Para jugar con la API, ejecuta la demo en Glitch. Asegúrate de consultar el código fuente.

Consideraciones de seguridad

Los autores de las especificaciones diseñaron e implementaron esta API con el núcleo, lo que incluye el control del usuario, la transparencia y la ergonomía. La capacidad de usar esta API está restringida principalmente por el mismo modelo de permisos que la API de Media Capture and Streams. En respuesta a un mensaje del usuario, el sitio web puede controlar la PTZ de la cámara solo cuando la página es visible para el usuario.

Compatibilidad del navegador

API de MediaStream

Navegadores compatibles

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

Origen

API de Permissions

Navegadores compatibles

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

Origen

API de Page Visibility

Navegadores compatibles

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

Origen

MediaDevices.getUserMedia()

Navegadores compatibles

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

Origen

MediaDevices.getSupportedConstraints()

Navegadores compatibles

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

Origen

MediaStreamTrack.applyConstraints()

Navegadores compatibles

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

Origen

MediaStreamTrack.getCapabilities()

Navegadores compatibles

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

Origen

MediaStreamTrack.getSettings()

Navegadores compatibles

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

Origen

Vínculos útiles

Agradecimientos

Joe Medley y Thomas Steiner revisaron este artículo. Gracias a Rijubrata Bhaumik y Eero Häkkinen de Intel por su trabajo en las especificaciones y la implementación. Imagen hero de Christina @ wocintechchat.com en Unsplash.