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

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

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

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

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

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