مقدمة عن إضافات الوسائط المشفرة

توفّر الإضافات المشفّرة للوسائط (EME) واجهة برمجة تطبيقات تتيح لتطبيقات الويب التفاعل مع أنظمة حماية المحتوى للسماح بتشغيل الصوت والفيديو المشفّرَين.

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

وتشكّل EME إضافةً إلى مواصفات HTMLMediaElement، ومن هنا جاء اسمها. تعني استخدام "الإضافة" أنّ استخدام المتصفِّح EME هو إجراء اختياري: إذا كان المتصفّح لا يتيح الوسائط المشفّرة، لن يتمكّن من تشغيل الوسائط المشفَّرة، ولكنّه ليس مطلوبًا للامتثال لمواصفات HTML. من مواصفات EME:

تستخدِم عمليات تنفيذ EME المكوّنات الخارجية التالية:

  • النظام الرئيسي: آلية حماية المحتوى (DRM). لا تحدِّد مبادرة إدارة الحقوق الرقمية للمحتوى المحمي (EME) أنظمة إدارة المفاتيح نفسها، باستثناء Clear Key (مزيد من المعلومات عن ذلك أدناه).
  • وحدة فك تشفير المحتوى (CDM): هي آلية برنامج أو جهاز من جهة العميل تتيح تشغيل الوسائط المشفَّرة. كما هو الحال مع أنظمة إدارة المفاتيح، لا تحدِّد مبادرة إدارة الحقوق الرقمية للمحتوى المحمي (EME) أي أنظمة إدارة حقوق رقمية، بل توفِّر واجهة للتطبيقات للتفاعل مع أنظمة إدارة الحقوق الرقمية المتاحة.
  • خادم (المفتاح) الترخيص: يتفاعل مع "وحدة تحكُّم إدارة البيانات (CDM)" لتوفير مفاتيح لفك تشفير الوسائط. تقع على عاتق التطبيق مسؤولية التفاوض مع خادم الترخيص.
  • خدمة الحِزم: تُشفِّر الوسائط لتوزيعها أو استخدامها.

يتفاعل التطبيق الذي يستخدم EME مع خادم ترخيص للحصول على مفاتيح لتفعيل فك التشفير، ولكن لا تشكّل هوية المستخدم والمصادقة جزءًا من EME. يتم استرداد المفاتيح لتفعيل تشغيل الوسائط بعد مصادقة المستخدم (اختياريًا). يجب على خدمات مثل Netflix مصادقة المستخدمين داخل تطبيق الويب: فعندما يسجّل المستخدم الدخول إلى التطبيق، يحدد التطبيق هوية المستخدم وامتيازاته.

كيف يعمل EME؟

في ما يلي كيفية تفاعل مكوّنات إدارة الحقوق الرقمية للمحتوى المحمي (EME)، وفقًا لمثال الرمز البرمجي التالي:

  1. يحاول أحد تطبيقات الويب تشغيل صوت أو فيديو يتضمنان بثًا مشفّرًا واحدًا أو أكثر.
  2. يرصد المتصفّح أنّ الوسائط مشفّرة (اطّلِع على المربّع أدناه لمعرفة كيفية حدوث ذلك) ويُطلق حدث encrypted مع البيانات الوصفية (initData) التي تم الحصول عليها من الوسائط حول التشفير.
  3. يعالج التطبيق حدث encrypted:
    1. إذا لم يتم ربط أي كائن MediaKeys بعنصر الوسائط، اختَر أولاً نظام مفاتيح متاح باستخدام navigator.requestMediaKeySystemAccess() للتحقّق من أنظمة المفاتيح المتاحة، ثم أنشِئ كائن MediaKeys لنظام مفاتيح متاح من خلال كائن MediaKeySystemAccess. يُرجى العِلم أنّه يجب بدء تشغيل عنصر MediaKeys قبل أول حدث encrypted. يحصل التطبيق على عنوان URL لخادم الترخيص بشكل مستقل عن اختيار نظام إدارة مفاتيح التشفير المتاح. يمثّل عنصر MediaKeys جميع المفاتيح المتاحة لفك تشفير الوسائط لعنصر صوت أو فيديو. ويمثّل هذا العنصر مثيلًا لخدمة إدارة المحتوى الرقمي (CDM) ويوفّر إمكانية الوصول إلى خدمة إدارة المحتوى الرقمي، وتحديدًا لإنشاء جلسات المفاتيح التي تُستخدَم للحصول على مفاتيح من خادم التراخيص.
    2. بعد إنشاء عنصر MediaKeys، يمكنك إسناده إلى عنصر الوسائط: setMediaKeys() يربط عنصر MediaKeys بعنصر HTMLMediaElement، حتى يمكن استخدام مفاتيحه أثناء التشغيل، أي أثناء فك التشفير.
  4. ينشئ التطبيق MediaKeySession من خلال الاتصال بـ createSession() على MediaKeys. يؤدي ذلك إلى إنشاء MediaKeySession، الذي يمثّل مدة صلاحية الترخيص ومفاتيحه.
  5. ينشئ التطبيق طلب ترخيص من خلال تمرير بيانات الوسائط التي تم الحصول عليها في معالِج encrypted إلى وحدة إدارة الحقوق الرقمية (CDM)، وذلك من خلال استدعاء generateRequest() في MediaKeySession.
  6. يُطلق "مدير إدارة الحقوق الرقمية" حدث message: وهو طلب للحصول على مفتاح من خادم ترخيص.
  7. يتلقّى العنصر MediaKeySession الحدث message ويُرسِل التطبيق رسالة إلى خادم الترخيص (عبر XHR مثلاً).
  8. يتلقّى التطبيق استجابة من خادم الترخيص ويُرسِل البيانات إلى وحدة إدارة الحقوق الرقمية باستخدام طريقة update() من MediaKeySession.
  9. يفكّ نظام إدارة الحقوق الرقمية تشفير الوسائط باستخدام المفاتيح الواردة في الترخيص. يمكن استخدام مفتاح صالح من أي جلسة ضمن MediaKey المرتبطة بعنصر الوسائط. سيصل نظام إدارة البيانات إلى المفتاح والسياسة، ويتم فهرستهما حسب معرّف المفتاح.
  10. يستأنف تشغيل الوسائط.

فو…

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

...ما هي المهمة التي تؤديها منصات إدارة المشروعات؟

لا يقدّم تطبيق EME في حدّ ذاته طريقة لفك تشفير الوسائط، بل يقدّم ببساطة واجهة برمجة تطبيقات لتطبيق ويب للتفاعل مع وحدات فك تشفير المحتوى.

لا تحدّد مواصفات EME الإجراءات التي تُنفذها منصّات إدارة الحقوق الرقمية (CDM)، وقد تتعامل منصّة إدارة الحقوق الرقمية مع فك ترميز الوسائط وفك تشفيرها أيضًا. من الأقل إلى الأكثر فعالية، هناك عدة خيارات محتملة لوظائف إدارة الحقوق الرقمية:

  • فك التشفير فقط، ما يتيح التشغيل باستخدام مسار الوسائط العادي، على سبيل المثال من خلال عنصر <video>.
  • فك التشفير وفك الترميز، ونقل لقطات الفيديو إلى المتصفّح لعرضها
  • فك التشفير وفك الترميز، والعرض مباشرةً في الجهاز (مثل وحدة معالجة الرسومات)

تتوفّر طرق متعدّدة لإتاحة منصّة إدارة البيانات لتطبيق ويب:

  • حِزم إدارة جهاز Chrome مع المتصفّح
  • توزيع خدمة إدارة البيانات (CDM) بشكل منفصل
  • إنشاء وحدة إدارة بيانات في نظام التشغيل
  • تضمين وحدة إدارة حقوق رقمية في البرامج الثابتة
  • تضمين وحدة إدارة البيانات (CDM) في الجهاز

لا تحدّد مواصفات EME كيفية إتاحة وحدة إدارة الحقوق الرقمية، ولكنّ المتصفّح يتحمّل في جميع الحالات مسؤولية التحقّق من وحدة إدارة الحقوق الرقمية وعرضها.

لا يفرض معيار EME استخدام نظام مفتاح معيّن. ومن بين متصفّحات أجهزة الكمبيوتر المكتبي والأجهزة الجوّالة الحالية، يتيح Chrome استخدام Widevine ويستخدم IE11 نظام PlayReady.

الحصول على مفتاح من خادم الترخيص

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

توضِّح التعليمة البرمجية التالية (المعدَّلة من أمثلة المواصفات) كيف يمكن للتطبيق اختيار نظام مفاتيح مناسب والحصول على مفتاح من خادم ترخيص.

var video = document.querySelector('video');

var config = [{initDataTypes: ['webm'],
  videoCapabilities: [{contentType: 'video/webm; codecs="vp9"'}]}];

if (!video.mediaKeys) {
  navigator.requestMediaKeySystemAccess('org.w3.clearkey',
      config).then(
    function(keySystemAccess) {
      var promise = keySystemAccess.createMediaKeys();
      promise.catch(
        console.error.bind(console, 'Unable to create MediaKeys')
      );
      promise.then(
        function(createdMediaKeys) {
          return video.setMediaKeys(createdMediaKeys);
        }
      ).catch(
        console.error.bind(console, 'Unable to set MediaKeys')
      );
      promise.then(
        function(createdMediaKeys) {
          var initData = new Uint8Array([...]);
          var keySession = createdMediaKeys.createSession();
          keySession.addEventListener('message', handleMessage,
              false);
          return keySession.generateRequest('webm', initData);
        }
      ).catch(
        console.error.bind(console,
          'Unable to create or initialize key session')
      );
    }
  );
}

function handleMessage(event) {
  var keySession = event.target;
  var license = new Uint8Array([...]);
  keySession.update(license).catch(
    console.error.bind(console, 'update() failed')
  );
}

التشفير الشائع

تسمح حلول "التشفير الشائع" لموفّري المحتوى بتشفير المحتوى وحزمه مرة واحدة لكل حاوية/ترميز واستخدامه مع مجموعة متنوعة من أنظمة إدارة المفاتيح وخدمات إدارة الحقوق الرقمية والعملاء، أي أي خدمة إدارة حقوق رقمية متوافقة مع "التشفير الشائع". على سبيل المثال، يمكن تشغيل فيديو تم حزمه باستخدام Playready في متصفّح باستخدام وحدة إدارة حقوق رقمية (CDM) من Widevine تحصل على مفتاح من خادم ترخيص Widevine.

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

التشفير الشائع (CENC) هو معيار ISO يحدِّد مخطّط حماية لتنسيق ISO BMFF، وينطبق مفهوم مشابه على WebM.

محو المفتاح

على الرغم من أن EME لا يحدد وظيفة إدارة الحقوق الرقمية، إلا أن المواصفات تفرض حاليًا على جميع المتصفحات التي تدعم EME تنفيذ مفتاح واضح. باستخدام هذا النظام، يمكن تشفير الوسائط باستخدام مفتاح ثم تشغيلها ببساطة من خلال تقديم هذا المفتاح. يمكن دمج Clear Key في المتصفّح: لا يتطلّب ذلك استخدام وحدة فك تشفير منفصلة.

على الرغم من أنّه من غير المرجّح استخدام Clear Key مع العديد من أنواع المحتوى التجاري، إلا أنّه يتوافق بشكل كامل مع جميع المتصفّحات التي تتيح استخدام EME. وهو مفيد أيضًا لاختبار عمليات تنفيذ EME والتطبيقات التي تستخدم EME، بدون الحاجة إلى طلب مفتاح محتوى من خادم ترخيص. يمكنك الاطّلاع على مثال بسيط على مفتاح Clear Key على الرابط simpl.info/ck. في ما يلي دليل تفصيلي للرمز البرمجي الذي يتطابق مع الخطوات الموضّحة أعلاه، ولكن بدون تفاعل مع خادم الترخيص.

// Define a key: hardcoded in this example
// – this corresponds to the key used for encryption
var KEY = new Uint8Array([
  0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
  0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c
]);

var config = [{
  initDataTypes: ['webm'],
  videoCapabilities: [{
    contentType: 'video/webm; codecs="vp8"'
  }]
}];

var video = document.querySelector('video');
video.addEventListener('encrypted', handleEncrypted, false);

navigator.requestMediaKeySystemAccess('org.w3.clearkey', config).then(
  function(keySystemAccess) {
    return keySystemAccess.createMediaKeys();
  }
).then(
  function(createdMediaKeys) {
    return video.setMediaKeys(createdMediaKeys);
  }
).catch(
  function(error) {
    console.error('Failed to set up MediaKeys', error);
  }
);

function handleEncrypted(event) {
  var session = video.mediaKeys.createSession();
  session.addEventListener('message', handleMessage, false);
  session.generateRequest(event.initDataType, event.initData).catch(
    function(error) {
      console.error('Failed to generate a license request', error);
    }
  );
}

function handleMessage(event) {
  // If you had a license server, you would make an asynchronous XMLHttpRequest
  // with event.message as the body.  The response from the server, as a
  // Uint8Array, would then be passed to session.update().
  // Instead, we will generate the license synchronously on the client, using
  // the hard-coded KEY at the top.
  var license = generateLicense(event.message);

  var session = event.target;
  session.update(license).catch(
    function(error) {
      console.error('Failed to update the session', error);
    }
  );
}

// Convert Uint8Array into base64 using base64url alphabet, without padding.
function toBase64(u8arr) {
  return btoa(String.fromCharCode.apply(null, u8arr)).
      replace(/\+/g, '-').replace(/\//g, '_').replace(/=*$/, '');
}

// This takes the place of a license server.
// kids is an array of base64-encoded key IDs
// keys is an array of base64-encoded keys
function generateLicense(message) {
  // Parse the clearkey license request.
  var request = JSON.parse(new TextDecoder().decode(message));
  // We only know one key, so there should only be one key ID.
  // A real license server could easily serve multiple keys.
  console.assert(request.kids.length === 1);

  var keyObj = {
    kty: 'oct',
    alg: 'A128KW',
    kid: request.kids[0],
    k: toBase64(KEY)
  };
  return new TextEncoder().encode(JSON.stringify({
    keys: [keyObj]
  }));
}

لاختبار هذا الرمز، تحتاج إلى فيديو مشفَّر لتشغيله. يمكن تشفير فيديو لاستخدامه مع Clear Key في WebM وفقًا لتعليماتwebm_crypt. تتوفّر أيضًا خدمات تجارية (لتنسيق ISO BMFF/MP4 على الأقل) ويتم تطوير حلول أخرى.

إضافات مصدر الوسائط (MSE)

HTMLMediaElement هو عنصر يتسم بجمال بسيط.

يمكننا تحميل الوسائط وفك ترميزها وتشغيلها ببساطة من خلال تقديم عنوان URL لعنصر src:

<video src='foo.webm'></video>

‫Media Source API هي إضافة إلى HTMLMediaElement تتيح التحكّم بشكل أدق في مصدر الوسائط، وذلك من خلال السماح لـ JavaScript بإنشاء أحداث بث لتشغيل الفيديو من "أجزاء" منه. ويؤدي ذلك بدوره إلى تفعيل تقنيات مثل البث التكيُّفي وتغيير الوقت.

ما أهمية MSE لميزة إدارة الحقوق الرقمية (EME)؟ ولأنّ موفّري المحتوى التجاري يجب أن يكونوا قادرين على تكييف عرض المحتوى مع ظروف الشبكة والمتطلبات الأخرى، بالإضافة إلى توزيع المحتوى المحمي. على سبيل المثال، تغيّر Netflix معدل نقل بيانات البث بشكل ديناميكي مع تغيّر ظروف الشبكة. تعمل واجهة EME مع تشغيل أحداث بث الوسائط المقدَّمة من خلال تنفيذ MSE، تمامًا كما تعمل مع الوسائط المقدَّمة من خلال سمة src.

كيف يمكن تقسيم الوسائط التي تم ترميزها بمعدّلات نقل بيانات مختلفة وتشغيلها؟ راجع قسم DASH أدناه.

يمكنك الاطّلاع على MSE أثناء التشغيل على الرابط simpl.info/mse. ولأغراض هذا المثال، تم تقسيم فيديو WebM إلى خمس أجزاء باستخدام واجهات برمجة تطبيقات File API. في تطبيق الإصدار العلني، سيتم استرداد أجزاء من الفيديو عبر Ajax.

أولاً، يتم إنشاء SourceBuffer:

var sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vorbis,vp8"');

بعد ذلك، يتم "بث" الفيلم بالكامل إلى عنصر فيديو من خلال إلحاق كل جزء باستخدام الطريقة appendBuffer()‎:

reader.onload = function (e) {
  sourceBuffer.appendBuffer(new Uint8Array(e.target.result));
  if (i === NUM_CHUNKS - 1) {
    mediaSource.endOfStream();
  } else {
    if (video.paused) {
      // start playing after first chunk is appended
      video.play();
    }
    readChunk_(++i);
  }
};

يمكنك الاطّلاع على مزيد من المعلومات عن MSE في مقالة HTML5 Rocks.

البث الديناميكي التكيُّفي عبر HTTP (DASH)

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

تم تصميم DASH (المعروف أيضًا باسم MPEG-DASH) لتقديم أفضل تجربة ممكنة لعرض الوسائط في ظروف الاتصال غير المستقر، سواء أثناء البث أو التنزيل. تُستخدم تقنيات أخرى مشابهة، مثل البث المباشر عبر بروتوكول HTTP (HLS) من Apple والبث السلس من Microsoft، ولكنّ DASH هي الطريقة الوحيدة لبث معدل نقل البيانات التكيُّفي عبر HTTP استنادًا إلى معيار مفتوح. يستخدم موقع YouTube وغيره من المواقع الإلكترونية حاليًا بروتوكول DASH.

ما علاقة ذلك بالميزتَين EME وMSE؟ يمكن لعمليات تنفيذ DASH المستندة إلى MSE تحليل بيان، وتنزيل مقاطع من الفيديو بمعدّل نقل بيانات مناسب، وإرسالها إلى عنصر فيديو عند الحاجة، وذلك باستخدام البنية الأساسية الحالية لبروتوكول HTTP.

بعبارة أخرى، تتيح DASH لموفّري المحتوى التجاري إجراء بث تكيُّفي للمحتوى المحمي.

تؤدي تقنية DASH ما وعدتك به:

  • ديناميكي: للاستجابة للظروف المتغيرة.
  • التحكّم التلقائي بالصوت: يتمّ ضبطه لتوفير معدل بت مناسب للصوت أو الفيديو.
  • البث: يتيح البث والتنزيل.
  • بروتوكول HTTP: يتيح هذا البروتوكول عرض المحتوى مع الاستفادة من مزايا بروتوكول HTTP، بدون السلبيات المرتبطة بخادم البث التقليدي.

بدأت BBC بتوفير أحداث بث تجريبية باستخدام DASH:

في ما يلي ملخّص:

  1. يتم ترميز الوسائط بمعدّلات نقل بيانات مختلفة.
  2. تتوفّر ملفات معدلات نقل البيانات المختلفة من خادم HTTP.
  3. يختار تطبيق الويب العميل معدّل نقل البيانات الذي سيتم استرجاعه وتشغيله باستخدام DASH.

كجزء من عملية تقسيم الفيديو، يتم إنشاء بيان XML يُعرف باسم وصف عرض الوسائط (MPD) آليًا. يصف هذا مجموعات التكيف والتمثيلات، مع المدد وعناوين URL. ويبدو MPD على النحو التالي:

<MPD xmlns="urn:mpeg:DASH:schema:MPD:2011" mediaPresentationDuration="PT0H3M1.63S" minBufferTime="PT1.5S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011"
type="static">
  <Period duration="PT0H3M1.63S" start="PT0S">
    <AdaptationSet>
      <ContentComponent contentType="video" id="1" />
      <Representation bandwidth="4190760" codecs="avc1.640028" height="1080" id="1" mimeType="video/mp4" width="1920">
        <BaseURL>car-20120827-89.mp4</BaseURL>
        <SegmentBase indexRange="674-1149">
          <Initialization range="0-673" />
        </SegmentBase>
      </Representation>
      <Representation bandwidth="2073921" codecs="avc1.4d401f" height="720" id="2" mimeType="video/mp4" width="1280">
        <BaseURL>car-20120827-88.mp4</BaseURL>
        <SegmentBase indexRange="708-1183">
          <Initialization range="0-707" />
        </SegmentBase>
      </Representation>

          </AdaptationSet>
  </Period>
</MPD>

(تم الحصول على ملف XML هذا من ملف ‎.mpd المستخدَم في مشغّل الإصدار التجريبي من YouTube DASH)

وفقًا لمواصفات DASH، يمكن نظريًا استخدام ملف MPD كsrc لفيديو. ومع ذلك، لمنح مطوّري الويب مزيدًا من المرونة، اختار مورّدو المتصفّحات بدلاً من ذلك ترك دعم DASH لمكتبات JavaScript التي تستخدم MSE، مثل dash.js. يتيح تنفيذ DASH في JavaScript تطوير خوارزمية التكيف بدون الحاجة إلى تحديثات المتصفّح. ويسمح استخدام الخطأ التربيعي المتوسط أيضًا بتجربة تنسيقات بديلة وآليات تسليم بدون الحاجة إلى إجراء تغييرات في المتصفّح. ينفِّذ Shaka Player من Google برنامج DASH متوافقًا مع EME.

تتضمّن شبكة مطوّري Mozilla تعليمات حول كيفية استخدام أدوات WebM وFFmpeg لتقسيم الفيديو وإنشاء ملف MPD.

الخاتمة

يزداد استخدام الويب لعرض الفيديوهات والمحتوى الصوتي المدفوع بمعدل هائل. يبدو أنّ كل جهاز جديد، سواء كان جهازًا لوحيًا أو وحدة تحكّم ألعاب أو تلفزيون متّصل أو جهاز فكّ ترميز المحتوى التلفزيوني، يمكنه بثّ الوسائط من مقدّمي المحتوى الرئيسيين عبر بروتوكول HTTP. تتوفّر علامتا <video> و<audio> الآن في أكثر من %85 من متصفّحات الأجهزة الجوّالة وأجهزة الكمبيوتر المكتبي، وتُقدّر شركة Cisco أنّ الفيديو سيشكّل نسبة تتراوح بين %80 و%90 من عدد زيارات المستهلكين على الإنترنت في جميع أنحاء العالم بحلول عام 2017. في هذا السياق، من المرجّح أن يزداد دور المتصفّحات في توزيع المحتوى المحمي، لأنّ مورّدي المتصفّحات يقتصرون على توفير الدعم لواجهات برمجة التطبيقات التي تعتمد عليها معظم مكوّنات الوسائط الإضافية.

مراجع إضافية

المواصفات والمعايير

مقالات