تم تجاوز حصة التخزين المؤقت

Joe Medley
Joe Medley

إذا كنت تعمل مع إضافات مصدر الوسائط (MSE)، أحد الأمور التي ستحتاج إلى التعامل معها في نهاية المطاف هو ذاكرة التخزين المؤقت المليئة بالمحتوى. وعندما يحدث ذلك، ستصلك رسالة تُعرف باسم QuotaExceededError. في هذه المقالة، سأتناول بعض طُرق التعامل مع هذه المشكلة.

ما هو QuotaExceededError؟

في الأساس، يشير الرمز QuotaExceededError إلى الخطأ الذي يظهر إذا حاولت إضافة بيانات كثيرة جدًا إلى عنصر SourceBuffer. (يمكن أن يؤدي أيضًا إضافة المزيد من عناصر SourceBuffer إلى عنصر MediaSource رئيسي إلى ظهور هذا الخطأ. يُرجى العِلم أنّ هذا الموضوع خارج نطاق هذه المقالة.) إذا كان SourceBuffer يحتوي على عدد كبير جدًا من البيانات، سيؤدي استدعاء SourceBuffer.appendBuffer() إلى عرض الرسالة التالية في نافذة وحدة تحكّم Chrome.

حدث خطأ في وحدة التحكم في الحصة.

في ما يلي بعض النقاط التي يجب أخذها في الاعتبار. أولاً، لاحظ أنّ الاسم QuotaExceededError لا يظهر في أي مكان في الرسالة. لمعرفة ذلك، يمكنك ضبط نقطة تفتيش في مكان يمكنك فيه رصد الخطأ وفحصه في نافذة المراقبة أو النطاق. لقد عرضت ذلك أدناه.

نافذة مشاهدة حصة التخزين

ثانيًا، لا تتوفّر طريقة محددة لمعرفة مقدار البيانات التي يمكن أن يعالجها SourceBuffer .

السلوك في المتصفّحات الأخرى

في وقت الكتابة، لم يطرح Safari QuotaExceededError في العديد من إصداراته. بدلاً من ذلك، تزيل الميزة اللقطات باستخدام خوارزمية من خطوتَين، وتتوقف إذا كانت هناك مساحة كافية لمعالجة appendBuffer(). أولاً، يتم تحرير اللقطات من الفترة التي تتراوح بين 0 و30 ثانية قبل الوقت الحالي، وذلك على شكل أجزاء مدتها 30 ثانية. بعد ذلك، يتم إخلاء اللقطات في أجزاء مدتها 30 ثانية من المدة إلى الوراء إلى أقرب وقت ممكن بعد 30 ثانية من currentTime. يمكنك قراءة المزيد من المعلومات عن هذا الموضوع في مجموعة تغييرات Webkit من عام 2014.

لحسن الحظ، يعرض Edge وFirefox هذا الخطأ أيضًا. إذا كنت تستخدم متصفّحًا آخر، عليك إجراء الاختبار بنفسك. على الرغم من أنّه قد لا يكون ما ستبنيه لمشغّل وسائط حقيقي، يتيح لك اختبار الحد الأقصى لسعة التخزين المؤقت للمصدر الذي أجراه "فرانسوا بافورت" على الأقل مراقبة السلوك.

كم عدد البيانات التي يمكنني إلحاقها؟

يختلف العدد الدقيق من متصفّح إلى آخر. بما أنّه لا يمكنك طلب معرفة مقدار البيانات المُلحَقة حاليًا، عليك تتبُّع مقدار البيانات المُلحَقة بنفسك. في ما يتعلّق بالمحتوى الذي يجب مشاهدته، إليك أفضل البيانات التي يمكنني جمعها في وقت كتابة هذه المقالة. بالنسبة إلى Chrome، هذه الأرقام هي الحدود القصوى، ما يعني أنّه يمكن أن تكون أصغر عندما يواجه النظام ضغطًا في الذاكرة.

Chrome ‫Chromecast* Firefox Safari Edge
فيديو ‫150 ميغابايت ‫30 ميغابايت 100 ميغابايت 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 ذلك من خلال استبدال دالة abort() فارغة في هذه الإصدارات من Safari.

إلحاق أجزاء أصغر

لقد شرحنا الإجراء أدناه. قد لا يعمل هذا في كل حالة، ولكن من الميزة أن يمكن تعديل حجم الأجزاء الأصغر لتناسب احتياجاتك. ولا تتطلّب هذه الطريقة أيضًا العودة إلى الشبكة، ما قد يؤدي إلى تحمُّل بعض المستخدمين لمزيد من تكاليف البيانات.

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

خفض درجة دقة التشغيل

يشبه ذلك إزالة البيانات الحديثة وإعادة الإلحاق. في الواقع، يمكن تنفيذ الأمرين معًا، على الرغم من أنّ المثال أدناه يعرض فقط خفض درجة الدقة.

هناك بعض النقاط التي يجب أخذها في الاعتبار عند استخدام هذه التقنية:

  • يجب إلحاق مقطع إعداد جديد. ويجب إجراء ذلك في أي وقت تُغيّر فيه التمثيلات. يجب أن يكون قسم الإعداد الجديد مخصّصًا لشرائح الوسائط التي تليها.
  • يجب أن يتطابق الطابع الزمني للعرض التقديمي للوسائط المُلحَقة مع الطابع الزمني للبيانات في المخزن المؤقت بأقرب شكل ممكن، ولكن يجب ألا يتخطى ذلك الطابع الزمني. قد يؤدي تداخُل البيانات المُخزَّنة مؤقتًا إلى حدوث تقطُّع أو توقف قصير حسب المتصفِّح. بغض النظر عن المحتوى الذي تُلحقه، لا تجعل المحتوى يتداخل مع مؤشر التشغيل، لأنّه سيؤدي ذلك إلى ظهور أخطاء.
  • قد يؤدي طلب الانتقال إلى لحظة معيّنة في الفيديو إلى إيقاف التشغيل. قد تميل إلى البحث عن موقع محدد واستئناف التشغيل من هناك. يُرجى العِلم أنّ هذا سيؤدي إلى انقطاع التشغيل إلى أن تكتمل عملية التقديم أو الإيقاف.