Jika Anda menggunakan Ekstensi Sumber Media (MSE), satu hal yang pada akhirnya
harus Anda tangani adalah buffering yang terlalu penuh. Jika hal ini terjadi, Anda akan
mendapatkan yang disebut QuotaExceededError
. Dalam artikel ini, saya akan membahas beberapa
cara untuk mengatasinya.
Apa yang dimaksud dengan QuotaExceededError?
Pada dasarnya, QuotaExceededError
adalah yang Anda dapatkan jika mencoba menambahkan terlalu banyak data ke objek SourceBuffer
. (Menambahkan objek SourceBuffer
lainnya 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.
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 memeriksanya di jendela pengamatan atau cakupan. Saya telah menunjukkan
ini di bawah.
Kedua, tidak ada cara pasti untuk mengetahui berapa banyak data yang dapat ditangani
oleh SourceBuffer
.
Perilaku di browser lain
Pada saat penulisan, Safari tidak menampilkan QuotaExceededError
di banyak build-nya. Sebagai gantinya, algoritma ini menghapus frame menggunakan algoritma dua langkah, yang berhenti jika
ada cukup ruang untuk menangani appendBuffer()
. Pertama, kode ini mengosongkan frame dari
antara 0 dan 30 detik sebelum waktu saat ini dalam potongan 30 detik. Selanjutnya, kode ini
akan mengosongkan frame dalam potongan 30 detik dari durasi mundur hingga mendekati 30
detik setelah currentTime
. Anda dapat membaca selengkapnya tentang hal ini di set perubahan Webkit dari tahun 2014.
Untungnya, bersama dengan Chrome, Edge, dan Firefox, error ini akan ditampilkan. Jika menggunakan browser lain, Anda harus melakukan pengujian sendiri. Meskipun mungkin bukan yang akan Anda build untuk pemutar media di dunia nyata, pengujian batas buffer sumber François Beaufort setidaknya memungkinkan Anda mengamati perilakunya.
Berapa banyak data yang dapat saya tambahkan?
Jumlah persisnya bervariasi dari browser ke browser. Karena Anda tidak dapat membuat kueri untuk jumlah data yang saat ini ditambahkan, Anda harus melacak jumlah data yang ditambahkan sendiri. Untuk konten yang ditonton, berikut ini data terbaik yang bisa saya kumpulkan saat menulis ini. Untuk Chrome, angka ini adalah batas atas yang berarti angka tersebut dapat lebih kecil saat sistem mengalami tekanan memori.
Chrome | Chromecast* | Firefox | Safari | Edge | |
---|---|---|---|---|---|
Video | 150 MB | 30 MB | 100MB | 290 MB | Tidak diketahui |
Audio | 12 MB | 2 MB | 15 MB | 14 MB | 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 didasarkan pada
pekerjaan berdasarkan jumlah yang Anda ambil dan coba tambahkan di luar
HTMLMediaElement.currentTime
dan menyesuaikan ukuran tersebut berdasarkan
QuotaExceededError
. Selain itu, menggunakan manifes seperti file mpd
(MPEG-DASH) atau file m3u8
(HLS) dapat membantu Anda melacak data yang ditambahkan ke buffering.
Sekarang, mari kita lihat beberapa pendekatan untuk menangani
QuotaExceededError
.
- Hapus data yang tidak diperlukan dan tambahkan kembali.
- Tambahkan fragmen yang lebih kecil.
- Turunkan resolusi pemutaran.
Meskipun keduanya dapat digunakan secara bersamaan, saya akan membahasnya satu per satu.
Menghapus data yang tidak diperlukan dan menambahkan ulang
Sebenarnya, fungsi ini harus disebut, "Hapus data yang paling tidak mungkin akan segera digunakan, lalu coba lagi penambahan data yang kemungkinan akan segera digunakan". Judul yang terlalu panjang. Anda hanya perlu mengingat apa yang sebenarnya saya maksud.
Menghapus data terbaru tidak sesederhana memanggil SourceBuffer.remove()
. Untuk
menghapus data dari SourceBuffer
, flag pembaruannya 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 pada pemutaran. Misalnya, jika Anda ingin video diputar ulang atau diulang segera, sebaiknya jangan hapus awal video. Demikian pula, jika Anda atau pengguna mencari bagian video tempat Anda telah menghapus data, Anda harus menambahkan data tersebut lagi untuk memenuhi penelusuran tersebut.
- Hapus sekonservatif mungkin. Berhati-hatilah saat menghapus grup frame yang sedang
diputar yang dimulai pada keyframe pada atau sebelum
currentTime
karena tindakan tersebut dapat menyebabkan pemutaran terhenti. Informasi tersebut mungkin perlu diurai keluar dari bytestream oleh aplikasi web jika tidak tersedia dalam manifes. Manifes media atau pengetahuan aplikasi tentang interval keyframe dalam media dapat membantu memandu pilihan rentang penghapusan aplikasi Anda untuk mencegah penghapusan media yang sedang diputar. Apa pun yang Anda hapus, jangan hapus grup gambar yang sedang diputar atau bahkan beberapa gambar pertama di luar grup tersebut. Secara umum, jangan menghapus di luar waktu saat ini kecuali Anda yakin bahwa media tersebut tidak diperlukan lagi. Jika Anda menghapusnya dekat dengan indicator pemutar, Anda dapat menyebabkan jeda. - Safari 9 dan Safari 10 tidak menerapkan
SourceBuffer.abort()
dengan benar. Bahkan, error tersebut akan menghentikan pemutaran. Untungnya, ada pelacak bug terbuka di sini dan di sini. Sementara itu, Anda harus mengatasinya. Shaka Player melakukannya dengan menonaktifkan fungsiabort()
kosong di versi Safari tersebut.
Menambahkan fragmen yang lebih kecil
Saya telah menunjukkan prosedurnya di bawah. Hal ini mungkin tidak berfungsi dalam setiap kasus, tetapi memiliki keuntungan bahwa ukuran potongan yang lebih kecil dapat disesuaikan sesuai kebutuhan Anda. Selain itu, beberapa pengguna tidak perlu kembali ke jaringan yang mungkin menimbulkan biaya data tambahan.
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
Tindakan ini mirip dengan menghapus data terbaru dan menambahkannya kembali. Faktanya, keduanya dapat dilakukan secara bersamaan, meskipun contoh di bawah 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 untuk segmen media yang mengikuti.
- Stempel waktu presentasi media yang ditambahkan harus cocok dengan stempel waktu data dalam buffer semirip mungkin, tetapi tidak boleh melompat lebih cepat. Tumpang-tindih data yang di-buffer dapat menyebabkan gangguan atau jeda singkat, bergantung pada browser. Apa pun yang Anda tambahkan, jangan tumpang-tindih dengan playhead karena hal ini akan menampilkan error.
- Mencari posisi dapat mengganggu pemutaran. Anda mungkin tergoda untuk mencari lokasi tertentu dan melanjutkan pemutaran dari sana. Perhatikan bahwa tindakan ini akan menyebabkan gangguan pemutaran hingga pencarian selesai.