web-dev-qa-db-fra.com

Capturez des images à partir de vidéos avec HTML5 et JavaScript

Je veux capturer une image de la vidéo toutes les 5 secondes.

Voici mon code 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);
}

Le problème que j'ai est que les deux premières images générées sont les mêmes et que l'image de durée-5 secondes n'est pas générée. J'ai découvert que la vignette est générée avant que l'image vidéo de l'heure spécifique ne s'affiche dans < video> tag.

Par exemple, lorsque video.currentTime = 5, l'image de la trame 0 est générée. Ensuite, l'image vidéo saute au temps 5s. Donc quand video.currentTime = 10, l'image de l'image 5s est générée.

39
Lin

Cause

Le problème est que la recherche de vidéo (en définissant c'est currentTime) est asynchrone.

Vous devez écouter l'événement seeked sinon il risque de prendre la trame actuelle réelle qui est probablement votre ancienne valeur.

Comme il est asynchrone, vous ne devez pas utiliser la setInterval() car elle est également asynchrone et vous ne pourrez pas synchroniser correctement lorsque la prochaine trame sera recherchée. Il n'est pas nécessaire d'utiliser setInterval() car nous utiliserons à la place l'événement seeked qui gardera tout synchronisé.

Solution

En réécrivant un peu le code, vous pouvez utiliser l'événement seeked pour parcourir la vidéo afin de capturer l'image correcte car cet événement nous garantit que nous sommes réellement à l'image que nous avons demandée en définissant currentTime propriété.

Exemple

// 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;
});

Ajoutez ce gestionnaire d'événements à la fête:

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
    }
});

Démo ici

48
user1693593