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

Joe Medley
Joe Medley

Si vous utilisez Media Source Extensions (MSE), vous devrez finir par un tampon trop complet. Dans ce cas, vous obtenez ce que l'on appelle un QuotaExceededError. Dans cet article, je vais vous expliquer comment résoudre ce problème.

Qu'est-ce que QuotaExceededError ?

QuotaExceededError est ce que vous obtenez si vous essayez d'ajouter trop de données à votre objet SourceBuffer. (L'ajout d'autres objets SourceBuffer à un élément MediaSource parent peut également générer cette erreur. Cela dépasse le cadre 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 la console des quotas.

Voici quelques points à noter à ce sujet. Tout d'abord, notez que le nom QuotaExceededError n'apparaît nulle part dans le message. Pour le voir, définissez un point d'arrêt à un endroit où vous pouvez intercepter l'erreur et l'examiner dans la fenêtre de montre ou de champ d'application. Je vous l’ai montré ci-dessous.

Fenêtre de surveillance du quota.

Deuxièmement, il n'existe aucun moyen définitif de connaître la quantité de données que le SourceBuffer peut gérer.

Comportement dans d'autres navigateurs

Au moment de la rédaction de ce document, Safari ne génère pas de QuotaExceededError dans bon nombre de ses compilations. Au lieu de cela, elle supprime les frames à l'aide d'un algorithme en deux étapes et s'arrête si l'espace disponible est suffisant pour gérer le appendBuffer(). Tout d'abord, elle libère les frames compris entre 0 et 30 secondes avant l'heure actuelle, par fragments de 30 secondes. Elle libère ensuite les frames par segments de 30 secondes, contre une durée réduite jusqu'à 30 secondes après currentTime. Pour en savoir plus, consultez l'ensemble de modifications Webkit de 2014.

Heureusement, comme Chrome, Edge et Firefox, vous générez cette erreur. Si vous utilisez un autre navigateur, vous devez effectuer vos propres tests. Bien que ce ne soit probablement pas ce que vous concevriez pour un lecteur multimédia réel, le test de limite de la mémoire tampon source de François Beaufort vous permet du moins d'observer le comportement.

Quelle quantité 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 devez effectuer le suivi de la quantité de données que vous ajoutez vous-même. Concernant les éléments à surveiller, voici les meilleures données que je peux recueillir au moment de la rédaction. Pour Chrome, il s'agit des limites supérieures qui peuvent être inférieures lorsque la mémoire système est sollicitée.

Chrome Chromecast* Firefox Safari Périphérie
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 Chrome à mémoire limitée.

Alors, que dois-je faire ?

Étant donné que la quantité de données acceptées 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 QuotaExceededError. Examinons maintenant quelques façons d’y parvenir.

Il existe plusieurs façons de gérer les QuotaExceededError. En réalité, il est préférable de combiner une ou plusieurs approches. Votre approche doit consister à baser le travail sur la quantité que vous récupérez et à ajouter au-delà de HTMLMediaElement.currentTime, et à 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 au tampon.

Examinons maintenant plusieurs approches permettant de gérer QuotaExceededError.

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

Bien qu'ils puissent être combinés, je vais les aborder un par un.

Supprimer les données inutiles et les ajouter à nouveau

En réalité, celui-ci doit s'appeler "Supprimer les données les moins susceptibles d'être utilisées bientôt, puis réessayer d'ajouter les données susceptibles d'être utilisées prochainement". Ce titre était trop long. Il vous suffit de vous souvenir de ce que je veux dire vraiment.

Pour supprimer des données récentes, il ne suffit pas d'appeler SourceBuffer.remove(). Pour que des données soient supprimées de SourceBuffer, la valeur de l'indicateur de mise à jour doit être "false". Si ce n'est pas le cas, appelez SourceBuffer.abort() avant de supprimer des données.

Veuillez tenir compte des points suivants 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 relancée ou lue rapidement en boucle, ne supprimez pas le début. 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 à nouveau ajouter ces données pour répondre à cette demande.
  • Soyez aussi prudent que possible. Veillez à supprimer le groupe d'images en cours de lecture commençant au niveau de l'image clé currentTime ou avant, car cela pourrait retarder la lecture. Ces informations peuvent avoir besoin d'être analysées hors du bytestream par l'application Web si elles ne sont pas disponibles dans le fichier manifeste. Un fichier manifeste multimédia ou une connaissance de l'application sur les intervalles d'images clés dans le contenu multimédia peut vous aider à choisir les plages de suppression pour votre application afin d'empêcher la suppression du contenu multimédia en cours de lecture. Quel que soit le groupe de photos en cours de lecture, ne le supprimez pas, ni même les premiers. En règle générale, ne supprimez pas le contenu au-delà de l'heure actuelle, sauf si vous êtes certain que le contenu multimédia n'est plus nécessaire. Si vous retirez la tête de lecture à proximité, vous risquez de bloquer la vidéo.
  • Safari 9 et Safari 10 n'implémentent pas correctement SourceBuffer.abort(). En fait, ils génèrent des erreurs qui interrompent la lecture. Heureusement, il existe des outils de suivi des bugs ouverts ici et ici. En attendant, vous allez devoir contourner ce problème. Shaka Player le fait en bouchons une fonction abort() vide sur ces versions de Safari.

Ajouter des fragments plus petits

Vous trouverez ci-dessous la procédure à suivre. Cela peut ne pas fonctionner dans tous les cas, mais l'avantage est que la taille des plus petits segments peut être ajustée en fonction de vos besoins. Il ne nécessite pas non plus 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);

Diminuer la résolution de lecture

Cette opération s'apparente à la suppression des données récentes et à l'ajout à nouveau. En fait, les deux peuvent être effectuées ensemble, bien que l'exemple ci-dessous ne montre que la réduction de la résolution.

Voici quelques éléments à 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 correspondre aux segments multimédias suivants.
  • Le code temporel de présentation du contenu multimédia ajouté doit correspondre le plus près possible à celui des données dans la mémoire tampon, mais ne doit pas avancer. Le chevauchement des données en mémoire tampon peut provoquer un saccade ou un blocage bref, selon le navigateur. Quel que soit ce que vous ajoutez, ne chevauchez pas la tête de lecture, car cela générerait des erreurs.
  • Une recherche peut interrompre la lecture. Vous serez peut-être tenté de rechercher un lieu spécifique et de reprendre la lecture à partir de là. Sachez que la lecture sera interrompue jusqu'à la fin de la recherche.