Controlar o movimento, a inclinação e o zoom da câmera

Os recursos de movimentação, inclinação e zoom em câmeras agora podem ser controlados na web.

François Beaufort
François Beaufort

As soluções de videoconferência em escala de sala usam câmeras com movimentação, inclinação e zoom (PTZ) para que o software possa apontar a câmera para uma reunião participantes. A partir do Chrome 87, os recursos de movimentação, inclinação e zoom câmeras estão disponíveis para sites que usam restrições de rastreamento de mídia em MediaDevices.getUserMedia() e MediaStreamTrack.applyConstraints().

Como usar a API

Detecção de recursos

A detecção de recursos para hardware é diferente do que você provavelmente já conhece. A presença dos nomes de restrição "pan", "tilt" e "zoom" em navigator.mediaDevices.getSupportedConstraints() informa que o navegador suporta a API para controlar o PTZ da câmera, mas não se o hardware da câmera oferece suporte a ele. A partir do Chrome 87, o controle da PTZ da câmera tem suporte em desktop, enquanto o Android ainda oferece suporte apenas para zoom.

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

Solicitar acesso a PTZ da câmera

Um site tem permissão para controlar o PTZ da câmera somente se o usuário concedeu à câmera a permissão PTZ por meio de um comando.

Para solicitar acesso à câmera PTZ, chame navigator.mediaDevices.getUserMedia() com as restrições de PTZ, como mostrado abaixo. Isso solicitará que o usuário conceda câmera e câmera comuns com permissões PTZ.

Captura de tela de uma solicitação de usuário PTZ de câmera no Chrome para macOS.
Comando do usuário da câmera PTZ.

A promessa retornada vai ser resolvida com um objeto MediaStream usado para mostrar o stream de vídeo da câmera para o usuário. Se a câmera não oferecer suporte a PTZ, o usuário receberá um comando comum da câmera.

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

Uma permissão de câmera concedida anteriormente, especificamente uma permissão sem acesso a PTZ não ganha automaticamente acesso à PTZ se estiver disponível. Isto é verdade mesmo quando a própria câmera é compatível com PTZ. A permissão precisa ser solicitada de novo. Felizmente, você pode usar a API Permissions para consultar e monitorar os status da permissão 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 se um navegador baseado no Chromium é compatível com PTZ para uma câmera, acesse interna do about://media-internals e confira a página "Pan-inclinação-Zoom" coluna na seção "Captura de vídeo" ; "inclinação panorâmica" e "zoom" respectivamente significam que a câmera oferece suporte a escala vertical e "Zoom (Absoluto)" Controles UVC. A tabela "Pan ponto (relativo)" e "Zoom (Relativo)" Os controles de UVC não são compatíveis com navegadores baseados no Chromium.

Captura de tela da página interna no ChromeOS para depurar o suporte à câmera PTZ.
Página interna para depurar o suporte à câmera PTZ.

Controlar PTZ da câmera

Manipular os recursos e configurações PTZ da câmera usando a visualização MediaStreamTrack do objeto stream recebido anteriormente. MediaStreamTrack.getCapabilities() retorna um dicionário com a recursos e os intervalos ou valores permitidos. Consequentemente, MediaStreamTrack.getSettings() retorna as configurações atuais.

As configurações e os recursos de movimentação, inclinação e zoom só estão disponíveis se forem compatíveis com o a câmera e o usuário concedeu a permissão PTZ a ela.

Como controlar a PTZ da câmera.

Chamar videoTrack.applyConstraints() com a função PTZ avançada restrições para controlar a movimentação, a inclinação e o zoom da câmera, conforme mostrado no exemplo abaixo. A promessa retornada será resolvida se for bem-sucedida. Caso contrário, será rejeitada se de uma destas formas:

  • a câmera com permissão PTZ não é concedida.
  • o hardware da câmera não oferece suporte à restrição PTZ.
  • a página não fica visível para o usuário. Use a API Page Visibility para detectar mudanças na visibilidade da 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...
}

Também é possível configurar a movimentação, a inclinação e o zoom da câmera chamando navigator.mediaDevices.getUserMedia() com alguma restrição ideal de PTZ de câmera e a distribuição dos valores dos dados. Isso é útil quando as capacidades PTZ da câmera são conhecidas com antecedência. Observação que restrições obrigatórias (mínima, máxima, exata) não são permitidas aqui.

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

Playground

Você pode testar a API executando a demonstração no Glitch. Não se esqueça de conferir o código-fonte.

Considerações de segurança

Os autores das especificações projetaram e implementaram essa API usando o núcleo incluindo controle do usuário, transparência e ergonomia. A possibilidade de usar A API é controlada principalmente pelo mesmo modelo de permissão que as APIs Media Capture e API Streams. Em resposta a um aviso do usuário, o site tem permissão para controlar PTZ da câmera somente quando a página estiver visível para o usuário.

Compatibilidade com navegadores

API MediaStream

Compatibilidade com navegadores

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

Origem

API Permissions

Compatibilidade com navegadores

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

Origem

API Page Visibility

Compatibilidade com navegadores

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

Origem

MediaDevices.getUserMedia()

Compatibilidade com navegadores

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

Origem

MediaDevices.getSupportedConstraints()

Compatibilidade com navegadores

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

Origem

MediaStreamTrack.applyConstraints()

Compatibilidade com navegadores

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

Origem

MediaStreamTrack.getCapabilities()

Compatibilidade com navegadores

  • Chrome: 59.
  • Borda: 12.
  • Firefox: incompatível.
  • Safari: 11

Origem

MediaStreamTrack.getSettings()

Compatibilidade com navegadores

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

Origem

Links úteis

Agradecimentos

Este artigo foi revisado por Joe Medley e Thomas Steiner. Agradecemos a Rijubrata Bhaumik e Eero Häkkinen, da Intel, pelo trabalho na e a implementação. Imagem principal de Christina @ wocintechchat.com no Unsplash.