Melebihi kuota buffering

Joe Medley
Joe Medley

Jika Anda bekerja dengan Ekstensi Sumber Media (MSE), satu hal yang pada akhirnya perlu Anda tangani adalah buffering yang terlalu penuh. Jika hal ini terjadi, Anda akan mendapatkan apa yang disebut QuotaExceededError. Dalam artikel ini, saya akan membahas beberapa cara untuk menanganinya.

Apa itu QuotaExceptionedError?

Pada dasarnya, QuotaExceededError adalah nilai yang Anda dapatkan jika mencoba menambahkan terlalu banyak data ke objek SourceBuffer. (Menambahkan lebih banyak objek SourceBuffer ke elemen MediaSource induk juga dapat menampilkan error ini. Hal ini berada di luar cakupan artikel ini.) Jika SourceBuffer memiliki terlalu banyak data di dalamnya, memanggil SourceBuffer.appendBuffer() akan memicu pesan berikut di jendela konsol Chrome.

Error konsol kuota.

Ada beberapa hal yang perlu diperhatikan tentang hal ini. Pertama, perhatikan bahwa nama QuotaExceededError tidak muncul di mana pun dalam pesan. Untuk melihatnya, tetapkan titik henti sementara di lokasi tempat Anda dapat menangkap error dan periksa di jendela smartwatch atau cakupan. Saya telah menunjukkannya di bawah ini.

Periode pantauan kuota.

Kedua, tidak ada cara pasti untuk mengetahui berapa banyak data yang dapat ditangani SourceBuffer.

Perilaku di browser lain

Pada saat penulisan ini, Safari tidak menampilkan QuotaExceededError di banyak build-nya. Sebaliknya, sistem akan menghapus frame menggunakan algoritme dua langkah, dan berhenti jika ada cukup ruang untuk menangani appendBuffer(). Pertama, ini membebaskan frame dari antara 0 dan 30 detik sebelum waktu saat ini dalam potongan 30 detik. Selanjutnya, metode ini membebaskan frame dalam potongan 30 detik dari durasi mundur hingga sedekat 30 detik setelah currentTime. Anda dapat membaca selengkapnya tentang hal ini di kumpulan perubahan Webkit dari tahun 2014.

Untungnya, bersama dengan Chrome, Edge, dan Firefox melakukan kesalahan ini. Jika Anda menggunakan browser lain, Anda harus melakukan pengujian sendiri. Meskipun mungkin bukan yang Anda buat untuk pemutar media di kehidupan nyata, pengujian batas buffer sumber François Beaufort setidaknya memungkinkan Anda mengamati perilaku tersebut.

Berapa banyak data yang dapat saya tambahkan?

Jumlah persisnya bervariasi dari satu browser ke browser lainnya. Karena Anda tidak dapat mengkueri jumlah data yang ditambahkan saat ini, Anda harus melacak jumlah yang ditambahkan sendiri. Tentang apa yang harus ditonton, berikut adalah data terbaik yang bisa saya kumpulkan pada saat artikel ini ditulis. Untuk Chrome, angka-angka ini adalah batas atas yang berarti akan lebih kecil ketika sistem mengalami tekanan memori.

Chrome Chromecast* Firefox Safari Edge
Video 150MB 30MB 100MB 290MB Tidak diketahui
Audio 12MB 2MB 15MB 14MB Tidak diketahui
  • Atau perangkat Chrome dengan memori terbatas lainnya.

Jadi, apa yang harus saya lakukan?

Karena jumlah data yang didukung sangat bervariasi dan Anda tidak dapat menemukan jumlah data dalam SourceBuffer, Anda harus mendapatkannya secara tidak langsung dengan menangani QuotaExceededError. Sekarang mari kita lihat beberapa cara untuk melakukannya.

Ada beberapa pendekatan untuk menangani QuotaExceededError. Pada kenyataannya, kombinasi dari satu atau beberapa pendekatan adalah yang terbaik. Pendekatan Anda harus mendasarkan pekerjaan pada jumlah yang Anda ambil dan coba tambahkan di luar HTMLMediaElement.currentTime dan menyesuaikan ukuran tersebut berdasarkan QuotaExceededError. Selain itu, menggunakan manifes semacam file mpd (MPEG-DASH) atau file m3u8 (HLS) dapat membantu Anda melacak data yang ditambahkan ke buffer.

Sekarang, mari kita lihat beberapa pendekatan untuk menangani QuotaExceededError.

  • Hapus data yang tidak diperlukan dan tambahkan kembali.
  • Menambahkan fragmen yang lebih kecil.
  • Menurunkan resolusi pemutaran.

Meskipun mereka dapat digunakan bersamaan, saya akan membahasnya satu per satu.

Hapus data yang tidak diperlukan dan tambahkan kembali

Benar-benar yang ini harus disebut, "Hapus data yang paling tidak mungkin digunakan segera, dan kemudian coba lagi penambahan data yang mungkin-akan-digunakan-segera." Judul terlalu panjang. Anda hanya perlu mengingat apa yang sebenarnya saya maksud.

Menghapus data terbaru tidak semudah memanggil SourceBuffer.remove(). Untuk menghapus data dari SourceBuffer, tanda yang diperbarui harus salah. Jika tidak, panggil SourceBuffer.abort() sebelum menghapus data apa pun.

Ada beberapa hal yang perlu diingat saat memanggil SourceBuffer.remove().

  • Hal ini dapat berdampak negatif terhadap pemutaran. Misalnya, jika Anda ingin video diputar ulang atau diulang, sebaiknya jangan menghapus awal video. Demikian pula, jika Anda atau pengguna mencari bagian video yang datanya telah dihapus, Anda harus menambahkan kembali data tersebut untuk memenuhi pencarian tersebut.
  • Hapus se konservatif mungkin. Hati-hati saat menghapus grup frame yang sedang diputar yang dimulai dari keyframe pada atau sebelum currentTime karena hal ini dapat menyebabkan pemutaran terhenti. Informasi tersebut mungkin perlu diurai dari bytestream oleh aplikasi web jika tidak tersedia di manifes. Manifes media atau pengetahuan aplikasi tentang interval keyframe di media dapat membantu memandu pilihan rentang penghapusan aplikasi untuk mencegah penghapusan media yang sedang diputar. Apa pun yang Anda hapus, jangan menghapus kumpulan gambar yang sedang diputar atau bahkan beberapa gambar pertama setelahnya. Secara umum, jangan menghapus di luar waktu saat ini kecuali Anda yakin bahwa media tidak diperlukan lagi. Jika Anda melepasnya di dekat playhead, pemutaran dapat terhenti.
  • Safari 9 dan Safari 10 tidak menerapkan SourceBuffer.abort() dengan benar. Bahkan, mereka akan menampilkan error yang akan menghentikan pemutaran. Untungnya ada pelacak bug terbuka di sini dan di sini. Sementara itu, Anda harus mengatasi hal ini. Shaka Player melakukannya dengan menghentikan fungsi abort() kosong pada versi Safari tersebut.

Menambahkan fragmen yang lebih kecil

Kami telah menampilkan prosedurnya di bawah ini. Cara ini mungkin tidak berfungsi di setiap kasus, tetapi untungnya ukuran potongan yang lebih kecil dapat disesuaikan dengan kebutuhan Anda. Metode ini juga tidak perlu kembali ke jaringan yang mungkin menimbulkan biaya data tambahan untuk beberapa pengguna.

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

Menurunkan resolusi pemutaran

Hal ini mirip dengan menghapus data terbaru dan menambahkan kembali. Sebenarnya, keduanya dapat dilakukan secara bersamaan, meskipun contoh di bawah ini hanya menunjukkan penurunan resolusi.

Ada beberapa hal yang perlu diingat saat menggunakan teknik ini:

  • Anda harus menambahkan segmen inisialisasi baru. Anda harus melakukannya setiap kali mengubah representasi. Segmen inisialisasi baru harus ditujukan untuk segmen media berikutnya.
  • Stempel waktu presentasi media yang ditambahkan harus semirip mungkin dengan stempel waktu data dalam buffer, tetapi tidak boleh melompat maju. Tumpang tindih dengan data yang di-buffer dapat menyebabkan tersendatnya atau berhenti sejenak, bergantung pada browser. Apa pun yang Anda tambahkan, jangan tumpang-tindih dengan titik pemutaran karena hal ini akan menampilkan error.
  • Pencarian dapat mengganggu pemutaran. Anda mungkin tergoda untuk mencari ke lokasi tertentu dan melanjutkan pemutaran dari sana. Perlu diketahui bahwa tindakan ini akan menyebabkan gangguan pemutaran hingga pencarian selesai.