javascript - txt - Genera una miniatura/instantánea de un archivo de video seleccionado por una entrada de archivo en un momento específico
read file javascript (1)
Hay cuatro pasos principales:
- Crea elementos
<canvas>
y<video>
. - Cargue el
src
del archivo de video generado porURL.createObjectURL
en el elemento<video>
y espere a que se cargue escuchando los eventos específicos que se activan . - Establezca el tiempo del video en el punto donde desea tomar una instantánea y escuchar eventos adicionales .
- Usa el lienzo para tomar la imagen.
Paso 1 - Crea los elementos
Esto es muy fácil: simplemente cree un elemento <canvas>
y un <video>
y añádalos a <body>
(o en cualquier lugar realmente, realmente no importa):
var canvasElem = $( ''<canvas class="snapshot-generator"></canvas>'' ).appendTo(document.body)[0];
var $video = $( ''<video muted class="snapshot-generator"></video>'' ).appendTo(document.body);
Observe que el elemento de video tiene el atributo muted
. No coloque ningún otro atributo como la autoplay
o los controls
. También note que ambos tienen el snapshot-generator
clase. Esto es para que podamos establecer el estilo para ambos, de modo que estén fuera del camino:
.snapshot-generator {
display: block;
height: 1px;
left: 0;
object-fit: contain;
position: fixed;
top: 0;
width: 1px;
z-index: -1;
}
Algunos navegadores funcionan con ellos configurados para display: none
, pero otros navegadores tendrán serios problemas a menos que se procesen en la página, por lo que los hacemos minúsculos para que sean esencialmente invisibles. (No los muevas fuera de la ventana gráfica, ya que de lo contrario, puedes ver algunas barras de desplazamiento feas en tu página).
Paso 2 - Cargar el video
Aquí es donde las cosas comienzan a ponerse difíciles. Necesita escuchar eventos para saber cuándo continuar. Diferentes navegadores lanzarán diferentes eventos, diferentes tiempos y en diferentes órdenes, así que te ahorraré el esfuerzo. Hay tres eventos que siempre deben activarse al menos una vez antes de que el video esté listo; son:
- loadedmetadata
- loadeddata
- suspender
Configure el controlador de eventos para estos eventos y realice un seguimiento de cuántos han disparado. Una vez que los tres han disparado, estás listo para continuar. Tenga en cuenta que, dado que algunos de estos eventos pueden dispararse más de una vez, solo desea controlar el primer evento de cada tipo que se dispara y descartar disparos posteriores. .one
de jQuery, que se encarga de esto.
var step_2_events_fired = 0;
$video.one(''loadedmetadata loadeddata suspend'', function() {
if (++step_2_events_fired == 3) {
// Ready for next step
}
}).prop(''src'', insert_source_here);
La fuente debe ser solo el objeto URL creado a través de URL.createObjectURL(file)
, donde el file
es el objeto de archivo.
Paso 3: establece el tiempo
Esta etapa es similar a la anterior: configure la hora y luego escuche un evento. Dentro de nuestro bloque if
del código anterior:
$video.one(''seeked'', function() {
// Ready for next step
}).prop(''currentTime'', insert_time_here_in_seconds);
Afortunadamente es el único evento esta vez, por lo que es bastante claro y conciso. Finalmente...
Paso 4: toma la instantánea
Esta parte solo usa el elemento <canvas>
para tomar una captura de pantalla. Dentro de nuestro controlador de eventos buscado:
canvas_elem.height = this.videoHeight;
canvas_elem.width = this.videoWidth;
canvas_elem.getContext(''2d'').drawImage(this, 0, 0);
var snapshot = canvas_elem.toDataURL();
// Remove elements as they are no longer needed
$video.remove();
$(canvas_elem).remove();
El lienzo debe coincidir con las dimensiones del video ( no el elemento <video>
) para obtener una imagen adecuada. Además, estamos configurando las propiedades internas .height
y .width
del lienzo , no los valores de estilo CSS de altura / ancho del lienzo.
El valor de la instantánea es un URI de datos, que básicamente es una cadena que comienza con los data:image/jpeg;base64
y luego los datos de base64.
Nuestro código JS final debería verse así:
var step_2_events_fired = 0;
$video.one(''loadedmetadata loadeddata suspend'', function() {
if (++step_2_events_fired == 3) {
$video.one(''seeked'', function() {
canvas_elem.height = this.videoHeight;
canvas_elem.width = this.videoWidth;
canvas_elem.getContext(''2d'').drawImage(this, 0, 0);
var snapshot = canvas_elem.toDataURL();
// Delete the elements as they are no longer needed
$video.remove();
$(canvas_elem).remove();
}).prop(''currentTime'', insert_time_here_in_seconds);
}
}).prop(''src'', insert_source_here);
¡Celebrar!
¡Tienes tu imagen en base64! Envíe esto a su servidor, póngalo como el src
de un elemento <img>
, o lo que sea.
Por ejemplo, puede decodificarlo en binario y escribirlo directamente en un archivo (recortar primero el prefijo) , que se convertirá en un archivo de imagen JPEG.
También puede usar esto para ofrecer vistas previas de videos mientras se cargan. Si lo está poniendo como el src
de un <img>
, use el URI de datos completo (no elimine el prefijo) .
¿Cómo capturo una instantánea de un archivo de video seleccionado mediante <input type="file">
en un momento específico del video silenciosamente en el fondo (es decir, sin elementos visibles, parpadeo, sonido, etc.)?