Capture frameworks de vídeo com HTML5 e JavaScript

Eu quero capturar um quadro de vídeo a cada 5 segundos.

Este é o meu código JavaScript:

video.addEventListener('loadeddata', function() { var duration = video.duration; var i = 0; var interval = setInterval(function() { video.currentTime = i; generateThumbnail(i); i = i+5; if (i > duration) clearInterval(interval); }, 300); }); function generateThumbnail(i) { //generate thumbnail URL data var context = thecanvas.getContext('2d'); context.drawImage(video, 0, 0, 220, 150); var dataURL = thecanvas.toDataURL(); //create img var img = document.createElement('img'); img.setAttribute('src', dataURL); //append img in container div document.getElementById('thumbnailContainer').appendChild(img); } 

O problema que tenho é que as primeiras duas imagens geradas são as mesmas e a duração de 5 segundos não é gerada. Descobri que a miniatura é gerada antes que o quadro de vídeo da hora específica seja exibido na tag .

Por exemplo, quando video.currentTime = 5 , a imagem do quadro 0s é gerada. Então o quadro de vídeo pula para o tempo 5s. Então, quando video.currentTime = 10 , a imagem do quadro 5s é gerada.

Causa

O problema é que procurar vídeo (definindo seu currentTime ) é asynchronous.

Você precisa ouvir o evento de seeked ou então arriscará pegar o quadro atual que provavelmente é seu valor antigo.

Como ele é asynchronous, você não deve usar o setInterval() pois ele é asynchronous e você não poderá sincronizar corretamente quando o próximo quadro for buscado. Não há necessidade de usar setInterval() pois utilizaremos o evento seeked , que manterá tudo sincronizado.

Solução

Reescrevendo o código um pouco, você pode usar o evento seeked para percorrer o vídeo para capturar o quadro correto, pois esse evento nos garante que estamos, na verdade, no quadro que solicitamos, definindo a propriedade currentTime .

Exemplo

 // global or parent scope of handlers var video = document.getElementById("video"); // added for clarity: this is needed var i = 0; video.addEventListener('loadeddata', function() { this.currentTime = i; }); 

Adicione este manipulador de events à festa:

 video.addEventListener('seeked', function() { // now video has seeked and current frames will show // at the time as we expect generateThumbnail(i); // when frame is captured increase, here by 5 seconds i += 5; // if we are not passed end, seek to next interval if (i <= this.duration) { // this will trigger another seeked event this.currentTime = i; } else { // Done!, next action } }); 

Demo aqui