Introducción
Nota: ya hay una versión 3 de este código. En ese nuevo post explico cómo dar la posibilidad de que el usuario cambie la cámara, además de que introduzco otras mejoras y actualizaciones. Míralo aquí.
Esta es la versión 2 de la primera entrada que escribí. Estaba probando la app en Chrome, y aparecía un mensaje que dice así:
[Deprecation] URL.createObjectURL with media streams is deprecated and will be removed in M68, around July 2018. Please use HTMLMediaElement.srcObject instead. See https://www.chromestatus.com/features/5618491470118912 for more details.
Quiere decir que el método que estamos utilizando es obsoleto y pronto será removido. Así que es hora de actualizar, cosa que no llevará más de medio minuto.
Lado del cliente
Los permisos se mantienen intactos, así como la petición AJAX. Lo único que cambia es la asignación del stream.
El código fuente original, es decir, el “desactualizado” se ve exactamente así:
/*
Tomar una fotografía y guardarla en un archivo
@date 2017-11-22
@author parzibyte
@web https://parzibyte.me/blog/
*/
function tieneSoporteUserMedia() {
return !!(navigator.getUserMedia || (navigator.mozGetUserMedia || navigator.mediaDevices.getUserMedia) || navigator.webkitGetUserMedia || navigator.msGetUserMedia)
}
function _getUserMedia() {
return (navigator.getUserMedia || (navigator.mozGetUserMedia || navigator.mediaDevices.getUserMedia) || navigator.webkitGetUserMedia || navigator.msGetUserMedia).apply(navigator, arguments);
}
// Declaramos elementos del DOM
var $video = document.getElementById("video"),
$canvas = document.getElementById("canvas"),
$boton = document.getElementById("boton"),
$estado = document.getElementById("estado");
if (tieneSoporteUserMedia()) {
_getUserMedia({
video: true
},
function(stream) {
console.log("Permiso concedido");
$video.src = window.URL.createObjectURL(stream);
$video.play();
//Escuchar el click
$boton.addEventListener("click", function() {
//Pausar reproducción
$video.pause();
//Obtener contexto del canvas y dibujar sobre él
var contexto = $canvas.getContext("2d");
$canvas.width = $video.videoWidth;
$canvas.height = $video.videoHeight;
contexto.drawImage($video, 0, 0, $canvas.width, $canvas.height);
var foto = $canvas.toDataURL(); //Esta es la foto, en base 64
$estado.innerHTML = "Enviando foto. Por favor, espera...";
var xhr = new XMLHttpRequest();
xhr.open("POST", "./guardar_foto.php", true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send(encodeURIComponent(foto)); //Codificar y enviar
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200) {
console.log("La foto fue enviada correctamente");
console.log(xhr);
$estado.innerHTML = "Foto guardada con éxito. Puedes verla <a target='_blank' href='./" + xhr.responseText + "'> aquí</a>";
}
}
//Reanudar reproducción
$video.play();
});
},
function(error) {
console.log("Permiso denegado o error: ", error);
$estado.innerHTML = "No se puede acceder a la cámara, o no diste permiso.";
});
} else {
alert("Lo siento. Tu navegador no soporta esta característica");
$estado.innerHTML = "Parece que tu navegador no soporta esta característica. Intenta actualizarlo.";
}
El cambio que tenemos que hacer es asignar directamente el stream a la propiedad srcObject del elemento vídeo. Ya no usamos window.URL.createObjectURL, sino que le asignamos el stream justo como viene. Así:
/*
Tomar una fotografía y guardarla en un archivo
@date 2017-11-22
@author parzibyte
@web https://parzibyte.me/blog/
*/
function tieneSoporteUserMedia() {
return !!(navigator.getUserMedia || (navigator.mozGetUserMedia || navigator.mediaDevices.getUserMedia) || navigator.webkitGetUserMedia || navigator.msGetUserMedia)
}
function _getUserMedia() {
return (navigator.getUserMedia || (navigator.mozGetUserMedia || navigator.mediaDevices.getUserMedia) || navigator.webkitGetUserMedia || navigator.msGetUserMedia).apply(navigator, arguments);
}
// Declaramos elementos del DOM
var $video = document.getElementById("video"),
$canvas = document.getElementById("canvas"),
$boton = document.getElementById("boton"),
$estado = document.getElementById("estado");
if (tieneSoporteUserMedia()) {
_getUserMedia({
video: true
},
function(stream) {
console.log("Permiso concedido");
$video.srcObject = stream;
$video.play();
//Escuchar el click
$boton.addEventListener("click", function() {
//Pausar reproducción
$video.pause();
//Obtener contexto del canvas y dibujar sobre él
var contexto = $canvas.getContext("2d");
$canvas.width = $video.videoWidth;
$canvas.height = $video.videoHeight;
contexto.drawImage($video, 0, 0, $canvas.width, $canvas.height);
var foto = $canvas.toDataURL(); //Esta es la foto, en base 64
$estado.innerHTML = "Enviando foto. Por favor, espera...";
var xhr = new XMLHttpRequest();
xhr.open("POST", "./guardar_foto.php", true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send(encodeURIComponent(foto)); //Codificar y enviar
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200) {
console.log("La foto fue enviada correctamente");
console.log(xhr);
$estado.innerHTML = "Foto guardada con éxito. Puedes verla <a target='_blank' href='./" + xhr.responseText + "'> aquí</a>";
}
}
//Reanudar reproducción
$video.play();
});
},
function(error) {
console.log("Permiso denegado o error: ", error);
$estado.innerHTML = "No se puede acceder a la cámara, o no diste permiso.";
});
} else {
alert("Lo siento. Tu navegador no soporta esta característica");
$estado.innerHTML = "Parece que tu navegador no soporta esta característica. Intenta actualizarlo.";
}
Lo único que cambia, como se ve, es la línea 26.
Con eso hemos actualizado el script para que no quede obsoleto. El lado del servidor, así como la vista, quedan intactos. Recuerda que esto es una modificación al código que vimos aquí.