web-dev-qa-db-fra.com

Comment détecter si la vidéo HTML5 s'est interrompue pour la mise en mémoire tampon?

J'essaie de tester si une vidéo est saccadée. J'ai remarqué que l'événement pause n'est pas déclenché lorsque la vidéo s'interrompt pour la mise en mémoire tampon. Quelle est la meilleure façon de détecter si la vidéo s'est interrompue pour la mise en mémoire tampon?

36
Supreet Totagi

Je l'ai fait en inspectant la progression du lecteur toutes les x millisecondes, par ex. 50. Si le joueur n'a pas avancé autant que prévu, nous tamponnons. C'est assez fiable, car j'ai trouvé que d'autres événements tels que waiting ou stalled ne sont pas déclenchés dans tous les cas de mise en mémoire tampon vidéo.

Notez que l'intervalle doit être plus grand que la différence inter-trame attendue, mais je suis sûr que vous ne voudrez pas être aussi précis de toute façon. Une estimation du temps de mise en mémoire tampon à ± 300 ms serait toujours correcte, étant donné que les humains ne peuvent très probablement pas percevoir de différences dans cette région.

Il est toutefois important de vérifier si l'utilisateur n'a pas activement interrompu la lecture.

var checkInterval  = 50.0 // check every 50 ms (do not use lower values)
var lastPlayPos    = 0
var currentPlayPos = 0
var bufferingDetected = false
var player = document.getElementById('videoPlayer')

setInterval(checkBuffering, checkInterval)
function checkBuffering() {
    currentPlayPos = player.currentTime

    // checking offset should be at most the check interval
    // but allow for some margin
    var offset = (checkInterval - 20) / 1000

    // if no buffering is currently detected,
    // and the position does not seem to increase
    // and the player isn't manually paused...
    if (
            !bufferingDetected 
            && currentPlayPos < (lastPlayPos + offset)
            && !player.paused
        ) {
        console.log("buffering")
        bufferingDetected = true
    }

    // if we were buffering but the player has advanced,
    // then there is no buffering
    if (
        bufferingDetected 
        && currentPlayPos > (lastPlayPos + offset)
        && !player.paused
        ) {
        console.log("not buffering anymore")
        bufferingDetected = false
    }
    lastPlayPos = currentPlayPos
}
43
slhck

L'événement que vous recherchez est waiting.

De la spec :

Un événement DOM en attente peut être déclenché à la suite d'un élément qui est en cours de lecture arrêtant la lecture en raison de la modification de son attribut readyState à une valeur inférieure à HAVE_FUTURE_DATA.

L'état paused ne change pas car la vidéo est toujours "potentiellement en cours de lecture" (c'est-à-dire "en train d'essayer" de jouer). L'événement waiting se déclenche donc. Lorsque suffisamment de données ont été chargées, playing se déclenche.

Vous pouvez également vérifier l'état à tout moment en consultant deux propriétés, networkState et readyState

if (video.networkState === video.NETWORK_LOADING) {
    // The user agent is actively trying to download data.
}

if (video.readyState < video.HAVE_FUTURE_DATA) {
    // There is not enough data to keep playing from this point
}
18
brianchirls

Vous pouvez simplement vérifier la durée du contenu vidéo en mémoire tampon et si elle est inférieure à la partie en cours de lecture, puis déclencher l'événement de pause.En utilisant le code suivant, vous pouvez vérifier la durée de la vidéo en mémoire tampon.

$vid = $("#video_id");

$vid.on('progress', function(e) {

    percentVidLoaded = null;
    // FF4+, Chrome
    if ($vid[0] && $vid[0].buffered && $vid[0].buffered.length > 0 && $vid[0].buffered.end && $vid[0].duration) {
        percentVidLoaded = $vid[0].buffered.end(0) / $vid[0].duration;
    }
    /* Some browsers (e.g., FF3.6 and Safari 5) cannot calculate target.bufferered.end()
     *  to be anything other than 0. If the byte count is available we use this instead.
     *  Browsers that support the else if do not seem to have the bufferedBytes value and
     *  should skip to there.
     */
    else if ($vid[0] && $vid[0].bytesTotal != undefined && $vid[0].bytesTotal > 0 && $vid[0].bufferedBytes != undefined) {
        percentVidLoaded = $vid[0].bufferedBytes / $vid[0].bytesTotal;
    }
    if (percentVidLoaded !== null) {
        percentVidLoaded = 100 * Math.min(1, Math.max(0, percentVidLoaded));
    }
});
1
Arjun Thakur

Vous devez vérifier si la mémoire tampon est inférieure à la durée vidéo actuelle. Si c'est le cas, la vidéo est mise en mémoire tampon. Cependant, vous devez vérifier cela avec une petite tolérance pour vous assurer de le détecter avant qu'il ne soit nécessaire de le tamponner.

Exemple:

var video = document.getElementById("myVideo");
var prevBuffer = {
    "buffer": null,
    "time": null
};
var isBuffering = function(){

    if(video && video.buffered && video.buffered.end && video.buffered.length > 0){
        var buffer = video.buffered.end(0);
        var time   = video.currentTime;

        // Check if the video hangs because of issues with e.g. performance
        if(prevBuffer.buffer === buffer && prevBuffer.time === time && !video.paused){
            return true;
        }
        prevBuffer = {
            "buffer": buffer,
            "time": time
        };
        // Check if video buffer is less
        // than current time (tolerance 3 sec)
        if((buffer - 3) < time){
            return true;
        }
    }
    return false;

};
video.addEventListener("play", function(e){
    // Make sure this handler is only called once
    e.target.removeEventListener(e.type, arguments.callee);
    // Give browsers 3secs time to buffer
    setTimeout(function(){
        // As "progress", "stalled" or "waiting" aren't fired
        // reliable, we need to use an interval
        var interval = setInterval(function(){
            if(isBuffering()){
                clearInterval(interval);
                console.log("Buffering");
            }
        }, 500);
    }, 3000);
});
0
dude