Atualmente, muitos navegadores têm o recurso de acessar inserções de dados de áudio e vídeo do usuário. No entanto, dependendo do navegador, essa pode ser uma experiência dinâmica e integrada ou delegada a outro app no dispositivo do usuário.
Comece de forma simples e progressiva
A coisa mais fácil a se fazer é simplesmente solicitar ao usuário um arquivo pré-gravado. Para isso, crie um elemento
de entrada de arquivo simples e adicione um filtro accept
que indique que só podemos aceitar arquivos de vídeo e
um atributo capture
que indique que queremos receber o arquivo diretamente da câmera.
<input type="file" accept="video/*" capture />
Esse método funciona em todas as plataformas. Em computadores, o usuário poderá fazer upload de um arquivo do
sistema de arquivos (ignorando o atributo capture
). No Safari
para iOS, ele vai abrir o app da câmera, permitindo gravar um vídeo e
enviar de volta para a página da Web. No Android, ele vai dar ao usuário a
opção de escolher qual app usar para gravar o vídeo antes de enviá-lo de volta para a página
da Web.
Muitos dispositivos móveis têm mais de uma câmera. Se você tiver uma preferência, defina o atributo capture
como user
, se quiser a câmera voltada para o usuário, ou environment
, se quiser a
câmera voltada para fora.
<input type="file" accept="video/*" capture="user" />
<input type="file" accept="video/*" capture="environment" />
Essa é apenas uma dica. Se o navegador não oferecer suporte à opção ou se o tipo de câmera solicitado não estiver disponível, o navegador poderá escolher outra câmera.
Quando o usuário terminar a gravação e for redirecionado ao site, você
precisa conseguir os dados do arquivo de alguma forma. É possível ter acesso rápido
anexando um evento onchange
ao elemento de entrada e lendo
a propriedade files
do objeto do evento.
<input type="file" accept="video/*" capture="camera" id="recorder" />
<video id="player" controls></video>
<script>
var recorder = document.getElementById('recorder');
var player = document.getElementById('player');
recorder.addEventListener('change', function (e) {
var file = e.target.files[0];
// Do something with the video file.
player.src = URL.createObjectURL(file);
});
</script>
Depois que você tiver acesso ao arquivo, pode fazer o que quiser com ele. Por exemplo, você pode:
- Anexá-lo diretamente a um elemento
<video>
para poder reproduzir - Fazer o download no dispositivo do usuário
- Faça upload dele em um servidor anexando-o a um
XMLHttpRequest
- Desenhar os frames em uma tela e aplicar filtros a eles
Embora usar o método do elemento "input" para acessar dados de vídeo seja universal, é a opção menos vantajosa. Queremos ter acesso à câmera e oferecer uma experiência bacana diretamente na página.
Acessar a câmera de forma interativa
Os navegadores modernos podem ter ligação direta com a câmera, permitindo criar experiências totalmente integradas com a página da Web, sem que o usuário precise sair do navegador.
Adquirir acesso à câmera
Podemos acessar a câmera diretamente usando uma API na especificação
WebRTC chamada getUserMedia()
. O getUserMedia()
vai solicitar ao usuário
acesso às câmeras e microfones conectados.
Se receber a autorização, a API retornará um Stream
que conterá os dados da câmera ou
do microfone. Em seguida, poderemos anexá-los a um elemento <video>
, a um stream
do WebRTC ou salvá-los usando a API MediaRecorder
.
Para receber dados da câmera, basta definir video: true
no objeto de restrições
que é transmitido à API getUserMedia()
.
<video id="player" controls></video>
<script>
var player = document.getElementById('player');
var handleSuccess = function (stream) {
player.srcObject = stream;
};
navigator.mediaDevices
.getUserMedia({audio: true, video: true})
.then(handleSuccess);
</script>
Se você quiser escolher uma câmera específica, primeiro enumere as câmeras disponíveis.
navigator.mediaDevices.enumerateDevices().then((devices) => {
devices = devices.filter((d) => d.kind === 'videoinput');
});
Em seguida, transmita o deviceId que você quer usar ao chamar getUserMedia
.
navigator.mediaDevices.getUserMedia({
audio: true,
video: {
deviceId: devices[0].deviceId,
},
});
Por si só, isso não é tão útil. Tudo que podemos fazer é pegar os dados do vídeo e reproduzir.
Acessar os dados brutos da câmera
Para acessar os dados brutos de vídeo da câmera, você pode desenhar cada frame em uma <canvas>
e
manipular os pixels diretamente.
Para uma tela 2D, use o método drawImage
do contexto para desenhar o frame atual de um
elemento <video>
na tela.
context.drawImage(myVideoElement, 0, 0);
Com uma tela WebGL, é possível usar um elemento <video>
como a origem de uma textura.
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
gl.RGBA,
gl.UNSIGNED_BYTE,
myVideoElement,
);
Em ambos os casos, o frame atual de um vídeo em reprodução será usado. Para processar vários frames, você precisa redesenhar o vídeo na tela toda vez.
Para saber mais, consulte nosso artigo sobre como aplicar efeitos em tempo real a imagens e vídeos.
Salvar os dados da câmera
A maneira mais fácil de salvar os dados da câmera é usar a
API MediaRecorder
.
A API MediaRecorder
vai usar o stream criado por getUserMedia
e, em seguida,
salvar progressivamente os dados do stream no destino escolhido.
<a id="download">Download</a>
<button id="stop">Stop</button>
<script>
let shouldStop = false;
let stopped = false;
const downloadLink = document.getElementById('download');
const stopButton = document.getElementById('stop');
stopButton.addEventListener('click', function() {
shouldStop = true;
})
var handleSuccess = function(stream) {
const options = {mimeType: 'video/webm'};
const recordedChunks = [];
const mediaRecorder = new MediaRecorder(stream, options);
mediaRecorder.addEventListener('dataavailable', function(e) {
if (e.data.size > 0) {
recordedChunks.push(e.data);
}
if(shouldStop === true && stopped === false) {
mediaRecorder.stop();
stopped = true;
}
});
mediaRecorder.addEventListener('stop', function() {
downloadLink.href = URL.createObjectURL(new Blob(recordedChunks));
downloadLink.download = 'acetest.webm';
});
mediaRecorder.start();
};
navigator.mediaDevices.getUserMedia({ audio: true, video: true })
.then(handleSuccess);
</script>
No nosso caso, estamos salvando os dados diretamente em uma matriz que poderemos transformar
em um Blob
, que pode ser usado para salvar no nosso servidor da Web ou diretamente
no espaço de armazenamento do dispositivo do usuário.
Peça permissão para usar a câmera com responsabilidade
Se o usuário ainda não tiver concedido acesso à câmera para o seu site,
no instante em que você chamar getUserMedia
, o navegador vai pedir que o usuário
autorize o seu site a acessar a câmera.
Os usuários odeiam receber solicitações de permissão de acesso a dispositivos importantes do seu aparelho e muitas vezes bloqueiam a solicitação ou a ignoram se não entendem por que a solicitação foi criada. A prática recomendada é só pedir acesso à câmera na primeira vez em que ela for necessária. Depois que o usuário conceder acesso, ele não vai receber mais solicitações de permissão de acesso. No entanto, se ele recusar o acesso, você não poderá solicitar a permissão do usuário de novo.
Use a API de permissões para verificar se você já tem acesso
A API getUserMedia
não informa se você já tem
acesso à câmera. Isso é um problema: para oferecer uma IU bacana
para fazer o usuário conceder acesso à câmera, você tem que pedir
acesso à câmera.
Esse problema pode ser resolvido em alguns navegadores por meio do uso da Permission API. A
API navigator.permission
permite consultar o estado da capacidade de
acessar APIs específicas sem ter que pedir novamente.
Para verificar se você tem acesso à câmera do usuário, transmita
{name: 'camera'}
no método de consulta. Ele vai retornar:
granted
: o usuário já deu acesso à câmera;prompt
: o usuário não deu acesso a você e vai receber uma solicitação quando você chamargetUserMedia
.denied
: o sistema ou o usuário bloqueou explicitamente o acesso à câmera, e você não poderá ter acesso a ela.
Agora você pode verificar rapidamente se precisa alterar sua interface do usuário para oferecer as ações que o usuário precisa tomar.
navigator.permissions.query({name: 'camera'}).then(function (result) {
if (result.state == 'granted') {
} else if (result.state == 'prompt') {
} else if (result.state == 'denied') {
}
result.onchange = function () {};
});