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 aplicativo 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" />
Isso é apenas uma dica: se o navegador não oferecer essa opção ou 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 acessar 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>
Quando tiver acesso ao arquivo, você poderá fazer o que quiser com ele. Por exemplo, você pode:
- Anexá-lo diretamente a um elemento
<video>
para poder reproduzir - Fazer o download para o 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.
Obter acesso à câmera
Podemos acessar a câmera diretamente usando uma API na especificação WebRTC
chamada getUserMedia()
. 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 acessar dados da câmera, basta definir video: true
no objeto de restrições
transmitido para a 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, você pode usar 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 depois podemos transformar
em uma Blob
que pode ser usada para salvar no nosso servidor da Web ou diretamente no
armazenamento no dispositivo do usuário.
Pedir permissão para usar a câmera com responsabilidade
Se o usuário ainda não tiver concedido acesso à câmera ao site,
no momento em que você chamar getUserMedia
, o navegador vai solicitar que o usuário
conceda permissão ao site para usar a câmera.
Os usuários odeiam receber solicitações de acesso a dispositivos avançados na máquina deles e, com frequência, bloqueiam a solicitação ou a ignoram se não entendem o contexto da solicitação. 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 apresenta um problema. Para fornecer uma boa interface
e fazer com que o usuário conceda acesso à câmera, você precisa 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 precisar solicitar 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 () {};
});