बफ़रिंग का कोटा खत्म हो गया है

जो मेडले
जो मेडली

अगर मीडिया सोर्स एक्सटेंशन (MSE) के साथ काम किया जा रहा है, तो आखिर में आपको ओवर-फ़ुल बफ़र करने की ज़रूरत होगी. ऐसा होने पर, आपको QuotaExceededError की जानकारी मिलेगी. इस लेख में, मैं इससे निपटने के कुछ तरीक़ों के बारे में बताऊँगा.

QUOTAExceedError क्या है?

आम तौर पर, जब आप अपने SourceBuffer ऑब्जेक्ट में बहुत ज़्यादा डेटा जोड़ने की कोशिश करते हैं, तो आपको QuotaExceededError मिलता है. (पैरंट MediaSource एलिमेंट में और SourceBuffer ऑब्जेक्ट जोड़ने पर भी यह गड़बड़ी हो सकती है. यह इस लेख के दायरे से बाहर है.) अगर SourceBuffer में बहुत ज़्यादा डेटा है, तो SourceBuffer.appendBuffer() को कॉल करने पर, Chrome की कंसोल विंडो में यह मैसेज दिखेगा.

कोटा कंसोल में गड़बड़ी.

इस बारे में ध्यान देने वाली कुछ बातें हैं. सबसे पहले, ध्यान दें कि मैसेज में QuotaExceededError नाम कहीं भी नहीं दिखता है. इसे देखने के लिए, उस जगह पर ब्रेकपॉइंट सेट करें जहां गड़बड़ी को पहचाना जा सके और अपनी स्मार्टवॉच या स्कोप विंडो में उसकी जांच की जा सके. मैंने इसे नीचे दिखाया है.

वॉच की तय सीमा.

दूसरी बात, यह पता करने का कोई तय तरीका नहीं है कि SourceBuffer कितना डेटा मैनेज कर सकता है.

अन्य ब्राउज़र में व्यवहार

लिखते समय, Safari अपने कई बिल्ड में QuotaExceededError नहीं फेंकता. इसके बजाय, यह दो स्टेप वाले एल्गोरिदम का इस्तेमाल करके फ़्रेम हटा देता है. अगर appendBuffer() को हैंडल करने के लिए जगह काफ़ी हो, तो यह रुक जाता है. पहला, यह मौजूदा समय से 0 से 30 सेकंड पहले तक के फ़्रेम को 30 सेकंड के हिस्से में दिखाता है. इसके बाद, यह फ़्रेम को 30 सेकंड के हिस्सों में बदलकर, पीछे की अवधि से currentTime के बाद 30 सेकंड तक सेट कर लेता है. इस बारे में ज़्यादा जानकारी के लिए, साल 2014 के वेबकिट के बदलावों का सेट लेख पढ़ें.

अच्छी बात यह है कि Chrome, Edge, और Firefox के साथ यह गड़बड़ी होती है. अगर किसी दूसरे ब्राउज़र का इस्तेमाल किया जा रहा है, तो आपको खुद ही टेस्ट करना होगा. यह मुमकिन है कि आपने रीयल-लाइफ़ मीडिया प्लेयर के लिए जो बनाया हो, वह शायद नहीं है. हालांकि, फ़्रैंसुआ बोफ़ोर्ट का सोर्स बफ़र लिमिट टेस्ट आपको व्यवहार के बारे में बताता है.

कितना डेटा जोड़ा जा सकता है?

हर ब्राउज़र के हिसाब से, यह संख्या अलग-अलग होती है. जोड़ने के बाद जोड़े गए मौजूदा डेटा के लिए क्वेरी नहीं की जा सकती. आपको यह देखना होगा कि कितना डेटा जोड़ा जा रहा है. अगर देखें कि क्या देखना है, तो लिखने के समय इकट्ठा होने वाला सबसे बेहतर डेटा दिखता है. Chrome के लिए ये संख्याएं ऊपरी सीमाएं होती हैं, इसका मतलब है कि सिस्टम के मेमोरी दबाव का सामना करने पर ये संख्याएं छोटी हो सकती हैं.

Chrome Chromecast* Firefox Safari Edge
वीडियो 150 एमबी 30 एमबी 100MB 290 एमबी कोई जानकारी नहीं है
ऑडियो 12 एमबी 2 एमबी 15 एमबी 14 एमबी कोई जानकारी नहीं है
  • या अन्य सीमित मेमोरी वाला Chrome डिवाइस.

तो मैं क्या करूं?

इस्तेमाल किया जा सकने वाला डेटा, काफ़ी अलग-अलग तरह का होता है और आपको SourceBuffer में भी नहीं दिख रहा डेटा होता है. इसलिए, आपको QuotaExceededError को मैनेज करके, इसे सीधे तौर पर नहीं पाना होगा. चलिए, अब ऐसा करने के कुछ तरीके देखते हैं.

QuotaExceededError का इस्तेमाल करने के कई तरीके हैं. असल में, एक या एक से ज़्यादा तरीकों को जोड़ना सबसे सही होता है. आपका तरीका इस बात पर आधारित होना चाहिए कि कितना डेटा फ़ेच किया जा रहा है और HTMLMediaElement.currentTime के बाद उसे जोड़ने की कोशिश की जा रही है. साथ ही, उस साइज़ को QuotaExceededError के हिसाब से अडजस्ट करना चाहिए. साथ ही, mpd फ़ाइल (MPEG-DASH) या m3u8 फ़ाइल (HLS) जैसे किसी मेनिफ़ेस्ट का इस्तेमाल करने से, बफ़र में जोड़े जा रहे डेटा को ट्रैक करने में मदद मिल सकती है.

आइए, अब QuotaExceededError से जुड़ी समस्याओं को हल करने के अलग-अलग तरीकों पर नज़र डालते हैं.

  • ग़ैर-ज़रूरी डेटा हटाएं और फिर से जोड़ें.
  • छोटे फ़्रैगमेंट जोड़ें.
  • वीडियो चलाने के रिज़ॉल्यूशन को कम करें.

हालांकि, इनका इस्तेमाल एक साथ किया जा सकता है, लेकिन मैं एक-एक करके उनके बारे में बताऊंगा.

ग़ैर-ज़रूरी डेटा हटाएं और फिर से जोड़ें

असल में, इस सवाल को यह कहा जाना चाहिए, "कम से कम संभावना वाला-से-इस्तेमाल किया जाने वाला-सून डेटा हटाएँ और फिर संभावित तौर पर इस्तेमाल होने वाला डेटा जोड़ने की फिर से कोशिश करें." यह एक शीर्षक का बहुत लंबा हिस्सा था. आपको बस मेरा मतलब याद रखना होगा.

हाल ही के डेटा को हटाना, SourceBuffer.remove() को कॉल करने जितना आसान नहीं है. SourceBuffer से डेटा हटाने के लिए, यह अपडेट हो रहा फ़्लैग गलत होना चाहिए. अगर ऐसा नहीं है, तो कोई भी डेटा हटाने से पहले SourceBuffer.abort() को कॉल करें.

SourceBuffer.remove() को कॉल करते समय कुछ बातों का ध्यान रखना ज़रूरी है.

  • इससे वीडियो चलाने की सुविधा पर बुरा असर पड़ सकता है. उदाहरण के लिए, अगर आपको वीडियो को जल्द से जल्द फिर से चलाना या लूप में चलाना है, तो हो सकता है कि आप वीडियो का शुरुआती हिस्सा न हटाना चाहें. इसी तरह, अगर आप या उपयोगकर्ता वीडियो का कोई ऐसा हिस्सा खोजते हैं जिससे आपने डेटा हटा दिया है, तो उस डेटा की क्वालिटी पूरी करने के लिए आपको वह डेटा फिर से जोड़ना होगा.
  • जितना हो सके, उतने पुराने तरीके से हटाएं. मुख्य-फ़्रेम पर शुरू होने वाले फ़्रेम के मौजूदा समूह को currentTime पर या इससे पहले हटाने से ध्यान रखें, क्योंकि ऐसा करने से वीडियो रुक सकता है. अगर मेनिफ़ेस्ट में ऐसी जानकारी उपलब्ध नहीं है, तो उसे वेब ऐप्लिकेशन से बाइटस्ट्रीम से पार्स करना पड़ सकता है. मीडिया मेनिफ़ेस्ट या मीडिया में मुख्य-फ़्रेम के अंतराल की जानकारी की मदद से, ऐप्लिकेशन को हटाने की सीमाएं चुनने में मदद मिलती है. इससे, मौजूदा समय में चल रहे मीडिया को हटाया नहीं जा सकता. चाहे आप जो भी हटाते हों, मौजूदा समय में चल रहे तस्वीरों के ग्रुप या उससे आगे के पहले कुछ ग्रुप को न हटाएं. आम तौर पर, मौजूदा समय के बाद की चीज़ों को तब तक न हटाएं, जब तक आप यह पक्का न कर लें कि मीडिया की अब ज़रूरत नहीं है. प्लेहेड को बहुत करीब से हटाने से, ऐप्लिकेशन के बंद होने की समस्या हो सकती है.
  • Safari 9 और Safari 10, SourceBuffer.abort() को सही तरीके से लागू नहीं करते. असल में, वे ऐसी गड़बड़ियां होती हैं जिनकी वजह से वीडियो चलने की सुविधा रुक जाती है. अच्छी बात यह है कि यहां और यहां ओपन बग ट्रैकर उपलब्ध हैं. इस बीच, आपको इस पर किसी तरह काम करना होगा. Shaka Player ने, Safari के उन वर्शन पर एक खाली abort() फ़ंक्शन का इस्तेमाल करके, ऐसा किया.

छोटे फ़्रैगमेंट जोड़ें

मैंने नीचे प्रक्रिया दिखाई है. ऐसा हो सकता है कि यह हर मामले में काम न करे, लेकिन इसका फ़ायदा यह है कि छोटे हिस्सों को आपकी ज़रूरत के हिसाब से बदला जा सकता है. इसके लिए, नेटवर्क पर वापस जाने की ज़रूरत भी नहीं है. इससे कुछ लोगों को डेटा के लिए अतिरिक्त शुल्क लग सकता है.

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

वीडियो का रिज़ॉल्यूशन कम करना

यह हाल ही के डेटा को हटाने और फिर से जोड़ने जैसा ही है. हो सकता है कि दोनों एक साथ किए जाते हों. हालांकि, नीचे दिए गए उदाहरण में सिर्फ़ रिज़ॉल्यूशन को कम करते हुए दिखाया गया है.

इस तकनीक का इस्तेमाल करते समय कुछ बातों का ध्यान रखना ज़रूरी है:

  • आपको एक नया इनिशलाइज़ेशन सेगमेंट जोड़ना होगा. जब भी आप प्रतिनिधि बदलते हैं, तो आपको ऐसा करना होगा. नया शुरू करने वाला सेगमेंट, आने वाले मीडिया सेगमेंट के लिए होना चाहिए.
  • जोड़ी गई मीडिया फ़ाइल के प्रज़ेंटेशन का टाइमस्टैंप, बफ़र में मौजूद डेटा के टाइमस्टैंप से जितना हो सके उतना मेल खाना चाहिए, लेकिन आगे नहीं बढ़ना चाहिए. बफ़र किए गए डेटा को ओवरलैप करने से, रुक-रुककर या थोड़े समय के लिए रुक सकता है, यह ब्राउज़र पर निर्भर करता है. चाहे आपने जो भी जोड़ा हो, प्लेहेड को ओवरलैप न करें, क्योंकि इससे गड़बड़ियां होंगी.
  • सीखने से वीडियो देखने में रुकावट आ सकती है. आप चाहें तो किसी खास जगह पर जाकर उस जगह से वीडियो चलाना फिर से शुरू करें. ध्यान रखें कि इससे वीडियो चलाने में तब तक रुकावट आएगी, जब तक वीडियो में आगे/पीछे जाने की प्रोसेस पूरी नहीं हो जाती.