One place for hosting & domains

      frontal

      Como acessar as câmeras frontal e traseira com o getUserMedia() do JavaScript


      Introdução

      Juntamente com o HTML5 foram introduzidas as APIs com acesso aos dispositivos de hardware, incluindo a API MediaDevices. Essa API fornece acesso aos dispositivos de entrada de mídia como áudio e vídeo.

      Com a ajuda dessa API, os desenvolvedores podem acessar dispositivos de áudio e vídeo para transmitir e exibir feeds de vídeo ao vivo no navegador. Neste tutorial, você irá acessar o feed de vídeo do dispositivo do usuário e exibi-lo no navegador usando o método getUserMedia.

      A API getUserMedia utiliza os dispositivos de entrada de mídia para produzir um MediaStream (transmissão de mídia). Esse MediaStream contém os tipos de mídia solicitados, seja áudio ou vídeo. Ao usar a transmissão retornada da API, é possível exibir os feeds de vídeo no navegador, o que é útil na comunicação em tempo real no navegador.

      Quando usado em conjunto com a API de gravação do MediaStream, é possível gravar e armazenar os dados de mídia capturados no navegador. Essa API só funciona em origens seguras assim como as APIs recentemente introduzidas, mas também funciona no localhost e URLs de arquivos.

      Pré-requisitos

      Este tutorial irá explicar inicialmente alguns conceitos e demonstrar exemplos com o Codepen. No passo final, você irá criar um feed de vídeo funcional para o navegador.

      Passo 1 — Verificando o suporte de dispositivos

      Primeiro, você verá como verificar se o navegador do usuário oferece suporte à API mediaDevices. Essa API existe dentra da interface do navegador e contém o estado atual e a identidade do agente do usuário. A verificação é realizada com o código a seguir que pode ser colado no Codepen:

      if ('mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices) {
        console.log("Let's get this party started")
      }
      

      Primeiro, ele verifica se a API mediaDevices existe dentro de navigator (navegador) e então verifica se a API getUserMedia está disponível dentro dos mediaDevices. Se o comando retorna true, podemos iniciar.

      Passo 2 — Solicitando a permissão do usuário

      Depois de confirmar que o navegador dá suporte à getUserMedia, é necessário solicitar a permissão para utilizar os dispositivos de entrada de mídia no agente do usuário. Normalmente, depois que o usuário concede a permissão, uma Promise é retornada e resolve para uma transmissão de mídia. Essa Promise não é retornada quando a permissão é negada pelo usuário, bloqueando o acesso a esses dispositivos.

      Cole a linha a seguir no Codepen para solicitar a permissão:

      navigator.mediaDevices.getUserMedia({video: true})
      

      O objeto fornecido como um argumento para o método getUserMedia chama-se constraints (restrições). Ele determina quais os dispositivos de entrada de mídia os quais você está solicitando permissão para acessar. Por exemplo, se o objeto contém audio: true, o usuário será solicitado a conceder acesso ao dispositivo de entrada de áudio.

      Passo 3 — Compreendendo as restrições de mídia

      Esta seção irá abordar o conceito geral de contraints. O objeto constraints é um objeto MediaStreamConstraints que especifica os tipos de mídia para solicitar e os requisitos de cada tipo de mídia. É possível especificar os requisitos para a transmissão solicitada usando o objeto constraints, como a resolução da transmissão a ser usada (front, back).

      É necessário especificar audio ou video ao fazer a solicitação. Um NotFoundError será retornado caso os tipos de mídia solicitados não possam ser encontrados no navegador do usuário.

      Se você pretende solicitar uma transmissão de vídeo de resolução 1280 x 720, atualize o objeto constraints para que fique assim:

      {
        video: {
          width: 1280,
          height: 720,
        }
      }
      

      Com essa atualização, o navegador tentará utilizar as configurações de qualidade especificadas para a transmissão. Se o dispositivo de vídeo não puder entregar essa resolução, o navegador retornará outras resoluções disponíveis.

      Para garantir que o navegador retorne uma resolução que não seja inferior àquela fornecida, será necessário utilizar a propriedade min. Aqui está como atualizar o objeto constraints para incluir a propriedade min:

      {
        video: {
          width: {
            min: 1280,
          },
          height: {
            min: 720,
          }
        }
      }
      

      Isso irá garantir que a resolução da transmissão retornada seja de pelo menos 1280 x 720. Caso esse requisito mínimo não possa ser atendido, a promessa será rejeitada com um OverconstrainedError.

      Em alguns casos, você pode ter a preocupação de salvar dados e precisa que a transmissão não ultrapasse uma determinada resolução. Isso pode ser útil nos casos em que o usuário esteja em um plano limitado. Para habilitar essa funcionalidade, atualize o objeto de restrições para que contenha um campo max:

      {
        video: {
          width: {
            min: 1280,
            max: 1920,
          },
          height: {
            min: 720,
            max: 1080
          }
        }
      }
      

      Com essas configurações, o navegador irá garantir que a transmissão de retorno não tenha resolução inferior a 1280 x 720 nem superior a 1920 x 1080.

      Outros termos que podem ser utilizados incluem exact e ideal. A configuração ideal é normalmente usada juntamente com as propriedades min e max para encontrar a melhor resolução possível, o mais perto dos valores ideais fornecidos.

      Atualize as restrições para incluir a palavra-chave ideal:

      {
        video: {
          width: {
            min: 1280,
            ideal: 1920,
            max: 2560,
          },
          height: {
            min: 720,
            ideal: 1080,
            max: 1440
          }
        }
      }
      

      Para fazer o navegador usar a câmera frontal ou traseira (em portáteis) nos dispositivos, especifique uma propriedade facingMode no objeto video:

      {
        video: {
          width: {
            min: 1280,
            ideal: 1920,
            max: 2560,
          },
          height: {
            min: 720,
            ideal: 1080,
            max: 1440
          },
          facingMode: 'user'
        }
      }
      

      Essa configuração irá utilizar a câmera frontal o tempo todo em todos os dispositivos. Para utilizar a câmera traseira em dispositivos móveis, altere a propriedade facingMode para environment.

      {
        video: {
          ...
          facingMode: {
            exact: 'environment'
          }
        }
      }
      

      Passo 4 — Usando o método enumerateDevices

      Quando o método enumerateDevices é chamado, ele retorna todos os dispositivos de entrada de mídia disponíveis no PC do usuário.

      Com esse método, é possível oferecer opções ao usuário sobre qual dispositivo de entrada de mídia usar para a transmissão de conteúdo de áudio ou vídeo. Esse método retorna uma Promise resolvida para uma matriz MediaDeviceInfo contendo informações sobre cada dispositivo.

      Um exemplo de como utilizar esse método é mostrado no trecho abaixo:

      async function getDevices() {
        const devices = await navigator.mediaDevices.enumerateDevices();
      }
      

      Uma amostra de resposta para cada um dos dispositivos se pareceria com a seguinte:

      {
        deviceId: "23e77f76e308d9b56cad920fe36883f30239491b8952ae36603c650fd5d8fbgj",
        groupId: "e0be8445bd846722962662d91c9eb04ia624aa42c2ca7c8e876187d1db3a3875",
        kind: "audiooutput",
        label: "",
      }
      

      Nota: um rótulo não será retornado a menos que uma transmissão esteja disponível, ou se o usuário tenha concedido permissões de acesso ao dispositivo.

      Passo 5 — Exibindo a transmissão de vídeo no navegador

      Até aqui, você passou pelo processo de solicitar e ganhar acesso aos dispositivos de mídia, configurou restrições para incluir as resoluções necessárias e selecionou a câmera que será utilizada para gravar o vídeo.

      Depois de todos esses passos, você irá pelo menos querer ver se a transmissão está sendo realizada com base nas configurações definidas. Para garantir isso, o elemento <video> será usado para exibir a transmissão de vídeo no navegador.

      Como mencionado anteriormente, o método getUserMedia retorna uma Promise que pode ser resolvida para uma transmissão. A transmissão retornada pode ser convertida em uma URL de objeto usando o método createObjectURL. Essa URL será definida como uma fonte de vídeo.

      Você irá criar uma pequena demonstração na qual deixamos o usuário escolher de sua lista de dispositivos de vídeo disponíveis usando o método enumerateDevices.

      Este é um método navigator.mediaDevices. Ele lista os dispositivos de mídia disponíveis, como microfones e câmeras. Depois retorna uma Promise resolvida para uma matriz de objetos detalhando os dispositivos de mídia disponíveis.

      Crie um arquivo index.html e atualize o conteúdo com o código abaixo:

      index.html

      <!doctype html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <meta name="viewport"
                content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
          <meta http-equiv="X-UA-Compatible" content="ie=edge">
          <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
          <link rel="stylesheet" href="style.css">
          <title>Document</title>
      </head>
      <body>
      <div class="display-cover">
          <video autoplay></video>
          <canvas class="d-none"></canvas>
      
          <div class="video-options">
              <select name="" id="" class="custom-select">
                  <option value="">Select camera</option>
              </select>
          </div>
      
          <img class="screenshot-image d-none" alt="">
      
          <div class="controls">
              <button class="btn btn-danger play" title="Play"><i data-feather="play-circle"></i></button>
              <button class="btn btn-info pause d-none" title="Pause"><i data-feather="pause"></i></button>
              <button class="btn btn-outline-success screenshot d-none" title="ScreenShot"><i data-feather="image"></i></button>
          </div>
      </div>
      
      <script src="https://unpkg.com/feather-icons"></script>
      <script src="script.js"></script>
      </body>
      </html>
      

      No trecho acima, foram configurados os elementos que serão necessários e alguns controles para o vídeo. Também foi incluído um botão para tirar capturas de tela do feed de vídeo atual.

      Agora, vamos adicionar um pouco de estilo a esses componentes.

      Crie um arquivo style.css e copie os estilos a seguir nele. O Bootstrap foi incluído para reduzir a quantidade de CSS que você precisará escrever para que os componentes sejam iniciados.

      style.css

      .screenshot-image {
          width: 150px;
          height: 90px;
          border-radius: 4px;
          border: 2px solid whitesmoke;
          box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1);
          position: absolute;
          bottom: 5px;
          left: 10px;
          background: white;
      }
      
      .display-cover {
          display: flex;
          justify-content: center;
          align-items: center;
          width: 70%;
          margin: 5% auto;
          position: relative;
      }
      
      video {
          width: 100%;
          background: rgba(0, 0, 0, 0.2);
      }
      
      .video-options {
          position: absolute;
          left: 20px;
          top: 30px;
      }
      
      .controls {
          position: absolute;
          right: 20px;
          top: 20px;
          display: flex;
      }
      
      .controls > button {
          width: 45px;
          height: 45px;
          text-align: center;
          border-radius: 100%;
          margin: 0 6px;
          background: transparent;
      }
      
      .controls > button:hover svg {
          color: white !important;
      }
      
      @media (min-width: 300px) and (max-width: 400px) {
          .controls {
              flex-direction: column;
          }
      
          .controls button {
              margin: 5px 0 !important;
          }
      }
      
      .controls > button > svg {
          height: 20px;
          width: 18px;
          text-align: center;
          margin: 0 auto;
          padding: 0;
      }
      
      .controls button:nth-child(1) {
          border: 2px solid #D2002E;
      }
      
      .controls button:nth-child(1) svg {
          color: #D2002E;
      }
      
      .controls button:nth-child(2) {
          border: 2px solid #008496;
      }
      
      .controls button:nth-child(2) svg {
          color: #008496;
      }
      
      .controls button:nth-child(3) {
          border: 2px solid #00B541;
      }
      
      .controls button:nth-child(3) svg {
          color: #00B541;
      }
      
      .controls > button {
          width: 45px;
          height: 45px;
          text-align: center;
          border-radius: 100%;
          margin: 0 6px;
          background: transparent;
      }
      
      .controls > button:hover svg {
          color: white;
      }
      

      O próximo passo é adicionar funcionalidade à demonstração. Usando o método enumerateDevices, você irá obter os dispositivos de vídeo disponíveis e os definirá como opções dentro do elemento selecionado. Crie um arquivo chamado script.js e atualize-o com o seguinte trecho:

      script.js

      feather.replace();
      
      const controls = document.querySelector('.controls');
      const cameraOptions = document.querySelector('.video-options>select');
      const video = document.querySelector('video');
      const canvas = document.querySelector('canvas');
      const screenshotImage = document.querySelector('img');
      const buttons = [...controls.querySelectorAll('button')];
      let streamStarted = false;
      
      const [play, pause, screenshot] = buttons;
      
      const constraints = {
        video: {
          width: {
            min: 1280,
            ideal: 1920,
            max: 2560,
          },
          height: {
            min: 720,
            ideal: 1080,
            max: 1440
          },
        }
      };
      
      const getCameraSelection = async () => {
        const devices = await navigator.mediaDevices.enumerateDevices();
        const videoDevices = devices.filter(device => device.kind === 'videoinput');
        const options = videoDevices.map(videoDevice => {
          return `<option value="${videoDevice.deviceId}">${videoDevice.label}</option>`;
        });
        cameraOptions.innerHTML = options.join('');
      };
      
      play.onclick = () => {
        if (streamStarted) {
          video.play();
          play.classList.add('d-none');
          pause.classList.remove('d-none');
          return;
        }
        if ('mediaDevices' in navigator && navigator.mediaDevices.getUserMedia) {
          const updatedConstraints = {
            ...constraints,
            deviceId: {
              exact: cameraOptions.value
            }
          };
          startStream(updatedConstraints);
        }
      };
      
      const startStream = async (constraints) => {
        const stream = await navigator.mediaDevices.getUserMedia(constraints);
        handleStream(stream);
      };
      
      const handleStream = (stream) => {
        video.srcObject = stream;
        play.classList.add('d-none');
        pause.classList.remove('d-none');
        screenshot.classList.remove('d-none');
        streamStarted = true;
      };
      
      getCameraSelection();
      

      No trecho acima, algumas coisas estão acontecendo. Vamos dividi-las:

      1. feather.replace(): essa chamada de método cria uma instância de feather, que é um ícone definido para o desenvolvimento Web.
      2. A variável constraints contém a configuração inicial para a transmissão. Ela será estendida para incluir o dispositivo de mídia escolhido pelo usuário.
      3. getCameraSelection: essa função chama o método enumerateDevices. Em seguida, você filtra a matriz gerada a partir da Promise resolvida e seleciona os dispositivos de entrada de vídeo. A partir dos resultados filtrados, você cria <option> para o elemento <select>.
      4. Chamar o método getUserMedia acontece dentro do ouvinte onclick do botão play. Aqui, você irá verificar se esse método é suportado pelo navegador do usuário antes de iniciar a transmissão.
      5. Em seguida, você irá chamar a função startStream que recebe um argumento constraints. Ela chama o método getUserMedia com as constraints fornecidas. O handleStream é chamado usando a transmissão da Promise resolvida. Esse método define a transmissão retornada para o srcObject do elemento de vídeo.

      Em seguida, você irá adicionar um listener de clique aos controles dos botões na página para pause, stop e tirar screenshots. Além disso, você irá adicionar um listener ao elemento <select> para atualizar as restrições da transmissão com o dispositivo de vídeo selecionado.

      Atualize o arquivo script.js com o código abaixo:

      script.js

      ...
      cameraOptions.onchange = () => {
        const updatedConstraints = {
          ...constraints,
          deviceId: {
            exact: cameraOptions.value
          }
        };
        startStream(updatedConstraints);
      };
      
      const pauseStream = () => {
        video.pause();
        play.classList.remove('d-none');
        pause.classList.add('d-none');
      };
      
      const doScreenshot = () => {
        canvas.width = video.videoWidth;
        canvas.height = video.videoHeight;
        canvas.getContext('2d').drawImage(video, 0, 0);
        screenshotImage.src = canvas.toDataURL('image/webp');
        screenshotImage.classList.remove('d-none');
      };
      
      pause.onclick = pauseStream;
      screenshot.onclick = doScreenshot;
      

      Agora, quando ao se abrir o arquivo index.html no navegador, clicar no botão Play irá iniciar a transmissão.

      Aqui está uma demonstração completa:

      Conclusão

      Esse tutorial introduziu a API getUserMedia. É uma adição interessante ao HTML5 que facilita o processo de captura de mídia na Web.

      A API recebe um parâmetro (constraints) que pode ser usado para configurar o acesso aos dispositivos de entrada de áudio e vídeo. Ela também pode ser usada para especificar a resolução de vídeo necessária para o seu aplicativo.

      É possível estender a demonstração ainda mais para dar ao usuário uma opção para salvar as capturas de tela feitas, bem como gravar e armazenar dados de vídeo e áudio com a ajuda da API MediaStream Recording.



      Source link