EME WTF?

Pengantar Ekstensi Media Terenkripsi

Ekstensi Media Terenkripsi menyediakan API yang memungkinkan aplikasi web berinteraksi dengan sistem perlindungan konten, sehingga memungkinkan pemutaran audio dan video terenkripsi.

EME didesain untuk memungkinkan aplikasi yang sama dan file terenkripsi untuk digunakan di browser apa pun, apa pun sistem perlindungan yang mendasarinya. Yang pertama dimungkinkan oleh API dan flow yang terstandardisasi, sedangkan yang kedua dimungkinkan oleh konsep Common Encryption.

EME adalah ekstensi untuk spesifikasi HTMLMediaElement - karena itulah namanya. Menjadi 'ekstensi' berarti bahwa dukungan browser untuk EME bersifat opsional: jika browser tidak mendukung media terenkripsi, browser tidak akan dapat memutar media terenkripsi, tetapi EME tidak diperlukan untuk kepatuhan spesifikasi HTML. Dari spesifikasi EME:

Implementasi EME menggunakan komponen eksternal berikut:

  • Sistem Utama: Mekanisme perlindungan konten (DRM). EME tidak mendefinisikan Sistem Kunci itu sendiri, selain Clear Key (informasi selengkapnya tentang hal itu ada di bawah).
  • Content Decryption Module (CDM): Mekanisme software atau hardware sisi klien yang memungkinkan pemutaran media terenkripsi. Seperti Sistem Kunci, EME tidak mendefinisikan CDM apa pun, tetapi menyediakan antarmuka bagi aplikasi untuk berinteraksi dengan CDM yang tersedia.
  • Server Lisensi (Kunci): Berinteraksi dengan CDM untuk memberikan kunci guna mendekripsi media. Negosiasi dengan server lisensi adalah tanggung jawab aplikasi.
  • Layanan pengemasan: Mengenkode dan mengenkripsi media untuk didistribusikan/konsumsi.

Perhatikan bahwa aplikasi yang menggunakan EME berinteraksi dengan server lisensi untuk mendapatkan kunci guna mengaktifkan dekripsi, tetapi identitas dan autentikasi pengguna bukan bagian dari EME. Pengambilan kunci untuk mengaktifkan pemutaran media dilakukan setelah (secara opsional) mengautentikasi pengguna. Layanan seperti Netflix harus mengautentikasi pengguna dalam aplikasi webnya: saat pengguna login ke aplikasi, aplikasi tersebut akan menentukan identitas dan hak istimewa pengguna.

Bagaimana cara kerja EME?

Berikut adalah cara komponen EME berinteraksi, sesuai dengan contoh kode di bawah ini:

  1. Aplikasi web mencoba memutar audio atau video yang memiliki satu atau beberapa streaming terenkripsi.
  2. Browser mengenali bahwa media dienkripsi (lihat kotak di bawah untuk mengetahui caranya) lalu mengaktifkan peristiwa encrypted dengan metadata (initData) yang diperoleh dari media tentang enkripsi.
  3. Aplikasi ini menangani peristiwa encrypted:
    1. Jika tidak ada objek MediaKeys yang dikaitkan dengan elemen media, pilih Sistem Kunci yang tersedia terlebih dahulu dengan menggunakan navigator.requestMediaKeySystemAccess() untuk memeriksa Sistem Kunci yang tersedia, lalu buat objek MediaKeys untuk Sistem Kunci yang tersedia melalui objek MediaKeySystemAccess. Perhatikan bahwa inisialisasi objek MediaKeys harus terjadi sebelum peristiwa encrypted pertama. Mendapatkan URL server lisensi dilakukan oleh aplikasi secara terpisah dari memilih sistem kunci yang tersedia. Objek MediaKeys mewakili semua kunci yang tersedia untuk mendekripsi media untuk elemen audio atau video. Otorisasi mewakili instance CDM dan memberikan akses ke CDM, khususnya untuk membuat sesi kunci, yang digunakan untuk mendapatkan kunci dari server lisensi.
    2. Setelah objek MediaKeys dibuat, tetapkan objek tersebut ke elemen media: setMediaKeys() mengaitkan objek MediaKeys dengan HTMLMediaElement, sehingga kuncinya dapat digunakan selama pemutaran, yaitu selama decoding.
  4. Aplikasi membuat MediaKeySession dengan memanggil createSession() pada MediaKeys. Tindakan ini akan membuat MediaKeySession, yang merepresentasikan masa berlaku lisensi dan kuncinya.
  5. Aplikasi akan membuat permintaan lisensi dengan meneruskan data media yang diperoleh di pengendali encrypted ke CDM, dengan memanggil generateRequest() di MediaKeySession.
  6. CDM mengaktifkan peristiwa message: permintaan untuk memperoleh kunci dari server lisensi.
  7. Objek MediaKeySession menerima peristiwa message dan aplikasi mengirimkan pesan ke server lisensi (misalnya melalui XHR).
  8. Aplikasi akan menerima respons dari server lisensi dan meneruskan data ke CDM menggunakan metode update() dari MediaKeySession.
  9. CDM mendekripsi media menggunakan kunci dalam lisensi tersebut. Kunci yang valid dapat digunakan, dari sesi mana pun dalam MediaKey yang terkait dengan elemen media. CDM akan mengakses kunci dan kebijakan tersebut, yang diindeks oleh ID Kunci.
  10. Pemutaran media dilanjutkan.

Fiuh...

Perhatikan bahwa mungkin ada beberapa pesan antara CDM dan server lisensi, dan semua komunikasi dalam proses ini buram bagi browser dan aplikasi: pesan hanya dipahami oleh CDM dan server lisensi, meskipun lapisan aplikasi dapat melihat jenis pesan yang dikirim CDM. Permintaan lisensi berisi bukti validitas CDM (dan hubungan kepercayaan) serta kunci yang akan digunakan saat mengenkripsi kunci konten dalam lisensi yang dihasilkan.

...tetapi apa yang sebenarnya dilakukan CDM?

Implementasi EME tidak dengan sendirinya menyediakan cara untuk mendekripsi media: implementasi hanya menyediakan API bagi aplikasi web untuk berinteraksi dengan Modul Dekripsi Konten.

Yang sebenarnya dilakukan CDM tidak ditentukan oleh spesifikasi EME, dan CDM dapat menangani decoding (dekompresi) media serta dekripsi. Dari yang paling tidak tangguh, ada beberapa opsi potensial untuk fungsi CDM:

  • Khusus dekripsi, yang memungkinkan pemutaran menggunakan pipeline media normal, misalnya melalui elemen <video>.
  • Dekripsi dan dekode, yang meneruskan frame video ke browser untuk rendering.
  • Dekripsi dan decoding, yang dirender secara langsung di hardware (misalnya, GPU).

Ada beberapa cara untuk menyediakan CDM bagi aplikasi web:

  • Paketkan CDM dengan browser.
  • Mendistribusikan CDM secara terpisah.
  • Membangun CDM ke dalam sistem operasi.
  • Menyertakan CDM dalam firmware.
  • Menyematkan CDM di hardware.

Bagaimana CDM tersedia tidak ditentukan oleh spesifikasi EME, tetapi dalam semua kasus, browser bertanggung jawab untuk memeriksa dan mengekspos CDM.

EME tidak mewajibkan {i>Key System<i} tertentu; di antara browser desktop dan seluler saat ini, Chrome mendukung Widevine dan IE11 mendukung PlayReady.

Mendapatkan kunci dari server lisensi

Dalam penggunaan komersial biasa, konten akan dienkripsi dan dienkode menggunakan layanan atau alat pengemasan. Setelah media terenkripsi disediakan secara online, klien web dapat memperoleh kunci (yang terdapat dalam lisensi) dari server lisensi dan menggunakan kunci tersebut untuk mengaktifkan dekripsi dan pemutaran konten.

Kode berikut (diadaptasi dari contoh spesifikasi) menunjukkan cara aplikasi memilih sistem kunci yang sesuai dan mendapatkan kunci dari server lisensi.

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

Enkripsi Umum

Solusi Enkripsi Umum memungkinkan penyedia konten mengenkripsi dan mengemas konten mereka sekali per penampung/codec dan menggunakannya dengan berbagai Sistem Kunci, CDM, dan klien: yaitu, CDM apa pun yang mendukung Enkripsi Umum. Misalnya, video yang dikemas menggunakan PlayReady dapat diputar di browser menggunakan Widevine CDM yang mendapatkan kunci dari server lisensi Widevine.

Hal ini berbeda dengan solusi lama yang hanya akan berfungsi dengan stack vertikal lengkap, termasuk satu klien yang sering kali juga menyertakan runtime aplikasi.

Common Encryption (CENC) adalah standar ISO yang menentukan skema perlindungan untuk ISO BMFF; konsep yang serupa berlaku untuk WebM.

Hapus Kunci

Meskipun EME tidak mendefinisikan fungsi DRM, spesifikasi saat ini mewajibkan semua browser yang mendukung EME untuk mengimplementasikan Clear Key. Dengan menggunakan sistem ini, media dapat dienkripsi dengan kunci, lalu diputar kembali hanya dengan memberikan kunci tersebut. Clear Key dapat dipasang ke dalam browser: tidak memerlukan penggunaan modul dekripsi terpisah.

Meskipun tidak mungkin digunakan untuk banyak jenis konten komersial, Clear Key dapat dioperasikan sepenuhnya di semua browser yang mendukung EME. Alat ini juga berguna untuk menguji implementasi EME, dan aplikasi yang menggunakan EME, tanpa perlu meminta kunci konten dari server lisensi. Ada contoh Clear Key sederhana di simpl.info/ck. Berikut adalah panduan kode, yang paralel dengan langkah-langkah yang dijelaskan di atas, meskipun tanpa interaksi server lisensi.

// 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]
  }));
}

Untuk menguji kode ini, Anda perlu video terenkripsi untuk diputar. Mengenkripsi video untuk digunakan dengan Clear Key dapat dilakukan untuk WebM sesuai dengan petunjuk webm_crypt. Layanan komersial juga tersedia (setidaknya untuk ISO BMFF/MP4) dan solusi lain sedang dikembangkan.

Ekstensi Sumber Media (MSE)

HTMLMediaElement adalah makhluk yang sangat menarik.

Kita dapat memuat, mendekode, dan memutar media hanya dengan memberikan URL src:

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

Media Source API adalah ekstensi untuk HTMLMediaElement yang memungkinkan kontrol lebih mendetail atas sumber media, dengan memungkinkan JavaScript membuat streaming untuk pemutaran dari 'bagian' video. Hal ini kemudian akan mengaktifkan teknik seperti streaming adaptif dan pergeseran waktu.

Mengapa MSE penting bagi EME? Karena selain mendistribusikan konten yang dilindungi, penyedia konten komersial juga harus dapat menyesuaikan penayangan konten dengan kondisi jaringan dan persyaratan lainnya. Netflix, misalnya, secara dinamis mengubah kecepatan bit streaming saat kondisi jaringan berubah. EME berfungsi dengan pemutaran streaming media yang disediakan oleh implementasi MSE, seperti halnya media yang disediakan melalui atribut src.

Bagaimana cara memotong dan memutar media yang dienkode pada kecepatan bit berbeda? Lihat bagian DASH di bawah ini.

Anda dapat melihat cara kerja MSE di simpl.info/mse; untuk tujuan contoh ini, video WebM dibagi menjadi lima bagian menggunakan File API. Dalam aplikasi produksi, potongan video akan diambil melalui Ajax.

Pertama, SourceBuffer dibuat:

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

Seluruh film kemudian 'di-streaming' ke elemen video dengan menambahkan setiap potongan menggunakan metode addBuffer():

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

Cari tahu lebih lanjut tentang MSE di artikel HTML5 Rocks.

Streaming Adaptif Dinamis melalui HTTP (DASH)

Multiperangkat, multi-platform, seluler - apa pun sebutannya, web sering kali diakses dalam kondisi konektivitas yang dapat berubah-ubah. Pengiriman dinamis dan adaptif sangat penting untuk mengatasi kendala bandwidth dan variabilitas dalam dunia multi-perangkat.

DASH (alias MPEG-DASH) dirancang untuk memungkinkan pengiriman media terbaik dalam dunia yang tak stabil, baik untuk streaming maupun download. Beberapa teknologi lain melakukan hal yang serupa - seperti HTTP Live Streaming (HLS) Apple dan Smooth Streaming Microsoft - tetapi DASH adalah satu-satunya metode streaming kecepatan bit adaptif melalui HTTP yang didasarkan pada standar terbuka. DASH sudah digunakan oleh situs seperti YouTube.

Apa hubungannya dengan EME dan MSE? Implementasi DASH berbasis MSE dapat mengurai manifes, mendownload segmen video pada kecepatan bit yang sesuai, dan memasukkannya ke elemen video saat merasa lapar, menggunakan infrastruktur HTTP yang ada.

Dengan kata lain, DASH memungkinkan penyedia konten komersial untuk melakukan streaming adaptif konten yang dilindungi.

DASH melakukan apa yang tertulis di kaleng:

  • Dinamis: merespons perubahan kondisi.
  • Adaptif: menyesuaikan kecepatan bit audio atau video yang sesuai.
  • Streaming: memungkinkan streaming serta download.
  • HTTP: memungkinkan pengiriman konten dengan keunggulan HTTP, tanpa kekurangan server streaming tradisional.

BBC telah mulai memberikan streaming pengujian menggunakan DASH:

Ringkasnya:

  1. Media dienkode pada kecepatan bit yang berbeda.
  2. File dengan kecepatan bit yang berbeda disediakan dari server HTTP.
  3. Aplikasi web klien memilih kecepatan bit mana yang akan diambil dan diputar dengan DASH.

Sebagai bagian dari proses segmentasi video, manifes XML yang dikenal sebagai Media Presentation Description (MPD) dibuat secara terprogram. Bagian ini menjelaskan Kumpulan Adaptasi dan Representasi, dengan durasi dan URL. MPD akan terlihat seperti ini:

<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 ini diambil dari file .mpd yang digunakan untuk pemutar demo DASH YouTube)

Menurut spesifikasi DASH, secara teori file MPD dapat digunakan sebagai src untuk suatu video. Namun, untuk memberikan lebih banyak fleksibilitas kepada developer web, vendor browser telah memilih untuk menyerahkan dukungan DASH ke library JavaScript menggunakan MSE seperti dash.js. Menerapkan DASH di JavaScript memungkinkan algoritma adaptasi berkembang tanpa memerlukan update browser. Penggunaan MSE juga memungkinkan eksperimen dengan format manifes alternatif dan mekanisme pengiriman tanpa memerlukan perubahan browser. Shaka Player Google mengimplementasikan klien DASH dengan dukungan EME.

Mozilla Developer Network memiliki petunjuk tentang cara menggunakan alat WebM dan FFmpeg untuk menyegmentasi video dan membuat MPD.

Kesimpulan

Penggunaan web untuk menayangkan video dan audio berbayar berkembang dengan tingkat besar. Tampaknya setiap perangkat baru, apakah itu tablet, konsol game, TV yang terhubung, atau dekoder, dapat menstreaming media dari penyedia konten utama melalui HTTP. Lebih dari 85% browser seluler dan desktop kini mendukung <video> dan <audio>, dan Cisco memperkirakan video akan mencapai 80 hingga 90 persen traffic internet konsumen global pada tahun 2017. Dalam konteks ini, dukungan browser untuk distribusi konten yang dilindungi kemungkinan akan menjadi semakin signifikan, karena vendor browser membatasi dukungan untuk API yang diandalkan oleh sebagian besar plugin media.

Bacaan lebih lanjut

Spesifikasi dan standar

Artikel