Arabelleğe alma kotasının aşılması

Ali Poşet
Ali Polat

Medya Kaynağı Uzantıları (MSE) ile çalışıyorsanız nihayetinde ihtiyacınız olan bir şey de aşırı dolu bir tampondur. Böyle bir durumda, QuotaExceededError adlı bir onayınız olur. Bu makalede, bu sorunla başa çıkmanın bazı yollarını ele alacağız.

QuotaExceededError nedir?

Özetle, SourceBuffer nesnenize çok fazla veri eklemeye çalışırsanız QuotaExceededError elde edersiniz. (Bir üst MediaSource öğesine daha fazla SourceBuffer nesnesi eklemek de bu hataya neden olabilir. Bu, bu makalenin kapsamı dışındadır.) SourceBuffer içinde çok fazla veri varsa SourceBuffer.appendBuffer() çağrısı yapıldığında Chrome konsol penceresinde aşağıdaki mesaj tetiklenir.

Kota konsolu hatası.

Bu konuda dikkat edilmesi gereken birkaç nokta var. Öncelikle QuotaExceededError adının iletinin hiçbir yerinde görünmediğine dikkat edin. Bunu görmek için hatayı yakalayabileceğiniz bir konumda ayrılma noktası belirleyin ve bunu izleme veya kapsam pencerenizde inceleyin. Bunu aşağıda gösteriyorum.

Kota izleme penceresi.

İkinci olarak, SourceBuffer uygulamasının ne kadar veri işleyebileceğini öğrenmenin kesin bir yolu yoktur.

Diğer tarayıcılardaki davranış

Bu yazının yazıldığı tarihte Safari, derlemelerinin çoğunda QuotaExceededError atamamıştır. Bunun yerine, iki adımlı bir algoritma kullanarak kareleri kaldırır ve appendBuffer() öğesinin işlenmesi için yeterli alan varsa durdurulur. İlk olarak 30 saniyelik parçalar halinde geçerli zamandan 0 ile 30 saniye arasındaki kareleri serbest bırakır. Daha sonra, 30 saniyelik parçalar halinde kareleri currentTime tarihinden sonra 30 saniyeye kadar bir süre geriye alır. Bu konuyla ilgili daha fazla bilgiyi 2014 Webkit değişiklikleri bölümünde bulabilirsiniz.

Neyse ki Chrome, Edge ve Firefox da bu hatayı bildiriyor. Başka bir tarayıcı kullanıyorsanız kendi testinizi yapmanız gerekir. Muhtemelen gerçek hayattaki bir medya oynatıcı için oluşturmak istediğiniz şey olmasa da, François Beaufort'un kaynak arabellek sınırı testi en azından davranışı gözlemlemenizi sağlar.

Ne kadar veri ekleyebilirim?

Kesin sayı, tarayıcıdan tarayıcıya değişir. Şu anda eklenmiş olan verileri sorgulayamayacağınızdan, ne kadar eklediğinizi izlemeniz gerekir. Ne izlememiz gerektiği konusunda, bu yazarken toplayabileceğim en iyi verileri burada bulabilirsiniz. Chrome için bu sayılar üst sınırlardır, yani sistem bellek baskısıyla karşılaştığında daha küçük olabilir.

Chrome Chromecast* Firefox Safari Edge
Video 150MB 30MB 100 MB 290MB Bilinmiyor
Ses 12MB 2MB 15 MB 14MB Bilinmiyor
  • Veya sınırlı belleğe sahip diğer Chrome cihazları.

Peki ne yapmam gerekir?

Desteklenen veri miktarı çok büyük değişiklik gösterdiği ve veri miktarını SourceBuffer içinde bulamadığınız için bu veriyi QuotaExceededError ile dolaylı olarak almalısınız. Şimdi bunu yapmanın birkaç yolunu inceleyelim.

QuotaExceededError ile ilgili çeşitli yaklaşımlar vardır. Aslına bakılırsa, bir veya daha fazla yaklaşımı bir arada kullanmak en iyisidir. Yaklaşımınız, çalışmanızı HTMLMediaElement.currentTime dışında ne kadar getirdiğinize ve eklemeye çalıştığınıza dayandırmak ve bu boyutu QuotaExceededError öğesine göre ayarlamak olmalıdır. Ayrıca mpd dosyası (MPEG-DASH) veya m3u8 dosyası (HLS) gibi bir tür manifest dosyası kullanarak arabelleğe eklediğiniz verileri takip edebilirsiniz.

Şimdi, QuotaExceededError ile başa çıkmaya yönelik birkaç yaklaşıma göz atalım.

  • Gereksiz verileri kaldırıp yeniden ekleyin.
  • Daha küçük parçalar ekleyin.
  • Oynatma çözünürlüğünü düşürün.

Bu iki yöntem birlikte kullanılabilir, ancak tek tek ele alacağız.

Gereksiz verileri kaldırıp yeniden ekleyin

Bunun adı, "Yakında kullanılma olasılığı en düşük olan verileri kaldırın, ardından kullanılması muhtemel verileri eklemeyi tekrar deneyin." Çok uzun bir başlıktı. Tek yapmanız gereken ne demek istediğimi unutmamak.

Son verileri kaldırmak, SourceBuffer.remove() numarasını aramak kadar kolay değildir. Verileri SourceBuffer öğesinden kaldırmak için güncelleme işaretinin "false" (yanlış) olması gerekir. Aynı değilse herhangi bir veriyi kaldırmadan önce SourceBuffer.abort() numaralı telefonu arayın.

SourceBuffer.remove() adlı kişiyi ararken aklınızda bulundurmanız gereken birkaç nokta vardır.

  • Bu durum, oynatma işlemini olumsuz yönde etkileyebilir. Örneğin, videonun kısa süre içinde tekrar oynatılmasını veya döngüye alınmasını istiyorsanız videonun başlangıcını kaldırmayın. Benzer şekilde, siz veya kullanıcı videonun verileri kaldırdığınız bir bölümünü ararsa bu aramayı karşılamak için söz konusu verileri tekrar eklemeniz gerekir.
  • Mümkün olduğunca ölçülü bir şekilde içerik kaldırın. Şu anda oynatılan kare grubunu, currentTime konumunda veya öncesinde animasyon karesinde başlayan karelerden çıkarmaktan kaçının. Bu işlem oynatmanın duraklamasına neden olabilir. Bu tür bilgilerin, manifest dosyasında mevcut değilse web uygulaması tarafından bayt akışından ayrıştırılması gerekebilir. Medyadaki animasyon karesi aralıklarıyla ilgili bir medya manifesti veya uygulama bilgisi, geçerli olarak oynatılan medyanın kaldırılmasını önlemek için uygulamanızın kaldırma aralıklarını seçmesine yardımcı olabilir. Neyi kaldırırsanız kaldırın, o anda oynatılan resim grubunu, hatta bunun dışındaki ilk resimleri bile kaldırmayın. Genellikle, medyaya artık ihtiyaç duyulmadığından emin olmadığınız sürece içeriği geçerli süreden sonra kaldırmayın. Video yer imlecinin yakınlarından çıkarırsanız oynamaya neden olabilirsiniz.
  • Safari 9 ve Safari 10, SourceBuffer.abort() kodunu doğru uygulaymıyor. Hatta oynatma işlemini durduracak hatalar verirler. Neyse ki burada ve burada açık hata izleyicileri bulabilirsiniz. Bu esnada da bir şekilde çözmeniz gerekir. Shaka Player bunu Safari'nin bu sürümlerinde boş bir abort() işlevini yok ederek yapar.

Daha küçük parçaları ekle

İşlemi aşağıda görebilirsiniz. Bu yöntem her durumda işe yaramayabilir ancak daha küçük parçaların boyutunun ihtiyaçlarınıza göre ayarlanabilmesi açısından avantaj sağlar. Ayrıca, ağa geri dönmenizi gerektirmez. Bu da bazı kullanıcılar için ek veri ücretlerine neden olabilir.

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

Oynatma çözünürlüğünü düşürme

Bu işlem, son verilerin kaldırılıp yeniden eklenmesine benzer. Aslında, bu ikisi birlikte yapılabilir. Bununla birlikte, aşağıdaki örnekte yalnızca çözünürlüğün düşürülmesi gösterilmektedir.

Bu tekniği kullanırken unutulmaması gereken birkaç nokta vardır:

  • Yeni bir başlatma segmenti eklemeniz gerekir. Bu işlemi temsilleri her değiştirdiğinizde yapmanız gerekir. Yeni başlatma segmenti, takip eden medya segmentleri için olmalıdır.
  • Eklenen medyanın sunum zaman damgası, arabellekteki verilerin zaman damgasıyla mümkün olduğunca yakın olmalı ancak ileriye atılmamalıdır. Arabelleğe alınan verilerin örtüşmesi, tarayıcıya bağlı olarak takılmaya veya kısa bir duraklamaya neden olabilir. Neyi eklerseniz ekleyin, video yer imlecinin üzerine gelmeyin. Aksi takdirde hatalara neden olur.
  • Arama yapmak, çalmayı kesintiye uğratabilir. Belirli bir konuma gidip oynatmayı o noktadan devam etmek isteyebilirsiniz. Bu durum, sarma işlemi tamamlanana kadar oynatma kesintisine neden olur.