Dépassement du quota de mise en mémoire tampon

Joe Medley
Joe Medley

Si vous travaillez avec des extensions de source multimédia (MSE), vous devrez éventuellement gérer un tampon trop plein. Dans ce cas, vous recevrez ce que l'on appelle une QuotaExceededError. Dans cet article, je vais vous présenter quelques-unes des solutions possibles.

Qu'est-ce que l'erreur QuotaExceededError ?

En gros, QuotaExceededError est ce que vous obtenez si vous essayez d'ajouter trop de données à votre objet SourceBuffer. (L'ajout d'objets SourceBuffer à un élément MediaSource parent peut également générer cette erreur. Cela n'entre pas dans le champ d'application de cet article.) Si SourceBuffer contient trop de données, l'appel de SourceBuffer.appendBuffer() déclenche le message suivant dans la fenêtre de la console Chrome.

Erreur de console de quota.

Quelques points à noter à ce sujet. Tout d'abord, notez que le nom QuotaExceededError n'apparaît nulle part dans le message. Pour le vérifier, définissez un point d'arrêt à un emplacement où vous pouvez intercepter l'erreur et l'examiner dans la fenêtre de surveillance ou de portée. Je l'ai illustré ci-dessous.

Fenêtre de surveillance des quotas.

Deuxièmement, il n'existe aucun moyen définitif de savoir combien de données SourceBuffer peut gérer.

Comportement dans d'autres navigateurs

Au moment de la rédaction de cet article, Safari n'émet pas de QuotaExceededError dans de nombreuses versions. Au lieu de cela, il supprime les frames à l'aide d'un algorithme en deux étapes, en s'arrêtant s'il y a suffisamment d'espace pour gérer appendBuffer(). Tout d'abord, il libère les images comprises entre 0 et 30 secondes avant l'heure actuelle, par blocs de 30 secondes. Ensuite, il libère les images par blocs de 30 secondes à partir de la durée à rebours jusqu'à 30 secondes après currentTime. Pour en savoir plus, consultez un changeset Webkit de 2014.

Heureusement, Chrome, Edge et Firefox génèrent cette erreur. Si vous utilisez un autre navigateur, vous devrez effectuer vos propres tests. Bien que ce ne soit probablement pas ce que vous créeriez pour un lecteur multimédia réel, le test de limite de tampon source de François Beaufort vous permet au moins d'observer le comportement.

Combien de données puis-je ajouter ?

Le nombre exact varie d'un navigateur à l'autre. Étant donné que vous ne pouvez pas interroger la quantité de données actuellement ajoutées, vous devrez suivre la quantité que vous ajoutez vous-même. En ce qui concerne les contenus à regarder, voici les meilleures données que je puisse recueillir au moment de la rédaction de cet article. Pour Chrome, ces chiffres correspondent à des limites supérieures, ce qui signifie qu'ils peuvent être inférieurs lorsque le système rencontre une pression de mémoire.

Chrome Chromecast* Firefox Safari Edge
Vidéo 150 Mo 30 Mo 100 Mo 290 Mo Inconnu
Audio 12 Mo 2 Mo 15 Mo 14 Mo Inconnu
  • Ou tout autre appareil Google Chrome à mémoire limitée.

Que dois-je faire ?

Étant donné que la quantité de données compatibles varie considérablement et que vous ne pouvez pas trouver la quantité de données dans un SourceBuffer, vous devez l'obtenir indirectement en gérant le QuotaExceededError. Voyons maintenant comment procéder.

Il existe plusieurs approches pour gérer les QuotaExceededError. En réalité, il est préférable de combiner une ou plusieurs approches. Votre approche doit être basée sur la quantité de données que vous récupérez et essayez d'ajouter au-delà de HTMLMediaElement.currentTime, et d'ajuster cette taille en fonction de QuotaExceededError. L'utilisation d'un fichier manifeste, tel qu'un fichier mpd (MPEG-DASH) ou un fichier m3u8 (HLS), peut également vous aider à suivre les données que vous ajoutez à la mémoire tampon.

Examinons maintenant plusieurs approches pour gérer QuotaExceededError.

  • Supprimez les données inutiles, puis ajoutez-les à nouveau.
  • Ajoutez des fragments plus petits.
  • Réduire la résolution de lecture.

Bien qu'ils puissent être utilisés ensemble, je vais les présenter individuellement.

Supprimer les données inutiles et ajouter à nouveau

Celui-ci doit être nommé "Supprimer les données qui sont les moins susceptibles d'être utilisées prochainement, puis réessayer d'ajouter les données susceptibles d'être utilisées prochainement". Ce titre était trop long. Il faudra juste que tu te souviennes de ce que je veux vraiment dire.

Supprimer des données récentes n'est pas aussi simple que d'appeler SourceBuffer.remove(). Pour supprimer des données de SourceBuffer, son indicateur de mise à jour doit être défini sur "false". Si ce n'est pas le cas, appelez SourceBuffer.abort() avant de supprimer des données.

Vous devez garder certains points à l'esprit lorsque vous appelez SourceBuffer.remove().

  • Cela peut avoir un impact négatif sur la lecture. Par exemple, si vous souhaitez que la vidéo soit rejouée ou mise en boucle rapidement, vous ne voudrez peut-être pas supprimer le début de la vidéo. De même, si vous ou l'utilisateur recherchez une partie de la vidéo dans laquelle vous avez supprimé des données, vous devrez ajouter à nouveau ces données pour répondre à cette recherche.
  • Supprimez le contenu de manière aussi conservatrice que possible. Veillez à ne pas supprimer le groupe de frames actuellement en cours de lecture à partir de l'image clé à currentTime ou avant, car cela pourrait entraîner un blocage de la lecture. Ces informations peuvent devoir être extraites du flux d'octets par l'application Web si elles ne sont pas disponibles dans le fichier manifeste. Un fichier manifeste multimédia ou la connaissance des intervalles de clés-images dans le contenu multimédia par l'application peuvent aider à guider le choix des plages de suppression de votre application pour éviter de supprimer le contenu multimédia en cours de lecture. Quel que soit ce que vous supprimez, ne supprimez pas le groupe d'images en cours de lecture ni les premières images au-delà. En règle générale, ne supprimez pas les éléments au-delà de l'heure actuelle, sauf si vous êtes certain qu'ils ne sont plus nécessaires. Si vous supprimez un élément à proximité du point de lecture, vous risquez de provoquer un blocage.
  • Safari 9 et Safari 10 n'implémentent pas correctement SourceBuffer.abort(). En fait, ils génèrent des erreurs qui arrêtent la lecture. Heureusement, il existe des outils de suivi des bugs ouverts ici et ici. En attendant, vous devrez trouver un moyen de contourner ce problème. Shaka Player le fait en remplaçant une fonction abort() vide sur ces versions de Safari.

Ajouter des fragments plus petits

Vous trouverez ci-dessous la procédure à suivre. Cela ne fonctionnera peut-être pas dans tous les cas, mais présente l'avantage que la taille des segments plus petits peut être ajustée en fonction de vos besoins. Il n'est pas non plus nécessaire de revenir au réseau, ce qui pourrait entraîner des coûts de données supplémentaires pour certains utilisateurs.

const pieces = new Uint8Array([data]);
(function appendFragments(pieces) {
    if (sourceBuffer.updating) {
    return;
    }
    pieces.forEach(piece => {
    try {
        sourceBuffer.appendBuffer(piece);
    }
    catch e {
        if (e.name !== 'QuotaExceededError') {
        throw e;
        }

        // Reduction schedule: 80%, 60%, 40%, 20%, 16%, 12%, 8%, 4%, fail.
        const reduction = pieces[0].byteLength * 0.8;
        if (reduction / data.byteLength < 0.04) {
        throw new Error('MediaSource threw QuotaExceededError too many times');
        }
        const newPieces = [
        pieces[0].slice(0, reduction),
        pieces[0].slice(reduction, pieces[0].byteLength)
        ];
        pieces.splice(0, 1, newPieces[0], newPieces[1]);
        appendBuffer(pieces);  
    }
    });
})(pieces);

Réduire la résolution de lecture

Cette opération est semblable à la suppression des données récentes et à leur ajout à nouveau. En fait, les deux peuvent être effectués ensemble, même si l'exemple ci-dessous ne montre qu'une réduction de la résolution.

Voici quelques points à garder à l'esprit lorsque vous utilisez cette technique :

  • Vous devez ajouter un nouveau segment d'initialisation. Vous devez le faire chaque fois que vous modifiez les représentations. Le nouveau segment d'initialisation doit concerner les segments multimédias qui suivent.
  • Le code temporel de présentation du contenu multimédia ajouté doit correspondre le plus précisément possible à celui des données du tampon, sans toutefois pouvoir aller plus loin. Le chevauchement des données mises en mémoire tampon peut entraîner un à-coup ou un arrêt momentané, selon le navigateur. Quel que soit ce que vous ajoutez, ne chevauchez pas la tête de lecture, car cela générera des erreurs.
  • La recherche peut interrompre la lecture. Vous pouvez être tenté de rechercher un emplacement spécifique et de reprendre la lecture à partir de là. Notez que cela interrompra la lecture jusqu'à la fin de la recherche.