Şifrelenmiş Medya Uzantılarına Giriş

Şifrelenmiş Medya Uzantıları (EME), web uygulamalarının şifrelenmiş ses ve videoların oynatılmasına izin vermek için içerik koruma sistemleriyle etkileşim kurmasını sağlayan bir API sağlar.

EME, temel koruma sisteminden bağımsız olarak aynı uygulamanın ve şifrelenmiş dosyaların herhangi bir tarayıcıda kullanılmasını sağlamak için tasarlanmıştır. İlki standartlaştırılmış API'ler ve akış sayesinde, ikincisi ise Ortak Şifreleme kavramı sayesinde mümkün olur.

EME, HTMLMediaElement spesifikasyonunun bir uzantısıdır. "Uzantı" olması, EME için tarayıcı desteğinin isteğe bağlı olduğu anlamına gelir: Şifrelenmiş medyayı desteklemeyen tarayıcılar şifrelenmiş medyayı oynatamaz ancak EME, HTML spesifikasyonuyla uyumluluk için gerekli değildir. EME spesifikasyonundan:

EME uygulamaları aşağıdaki harici bileşenleri kullanır:

  • Anahtar Sistem: İçerik koruma (DRM) mekanizması. EME, Açık Anahtar dışında anahtar sistemlerini kendisi tanımlamaz (bu konu hakkında daha fazla bilgiyi aşağıda bulabilirsiniz).
  • İçerik Şifre Çözme Modülü (CDM): Şifrelenmiş medyanın oynatılmasını sağlayan istemci tarafı yazılım veya donanım mekanizması. Anahtar sistemlerinde olduğu gibi EME de herhangi bir CDM tanımlamaz ancak uygulamaların mevcut CDM'lerle etkileşim kurması için bir arayüz sağlar.
  • Lisans (Anahtar) sunucusu: Medya şifresinin çözülmesi için anahtarlar sağlamak üzere CDM ile etkileşim kurar. Lisans sunucusuyla pazarlık yapmak uygulamanın sorumluluğundadır.
  • Ambalajlama hizmeti: Medyayı dağıtım/tüketim için kodlar ve şifreler.

EME kullanan bir uygulamanın, şifre çözmeyi etkinleştirmek için anahtarları almak üzere bir lisans sunucusuyla etkileşime geçtiğini ancak kullanıcı kimliğinin ve kimlik doğrulamasının EME'nin bir parçası olmadığını unutmayın. Medya oynatmayı etkinleştirmek için anahtarların alınması, kullanıcının kimliği (isteğe bağlı olarak) doğrulandıktan sonra gerçekleşir. Netflix gibi hizmetler, kullanıcıların web uygulamalarında kimliklerini doğrulamalıdır: Kullanıcı uygulamada oturum açtığında uygulama, kullanıcının kimliğini ve ayrıcalıklarını belirler.

EME nasıl çalışır?

Aşağıdaki kod örneğine karşılık gelen EME bileşenlerinin etkileşimi aşağıdaki gibidir:

  1. Bir web uygulaması, bir veya daha fazla şifrelenmiş yayın içeren ses veya video oynatmaya çalışır.
  2. Tarayıcı, medyanın şifrelenmiş olduğunu algılar (bu işlemin nasıl gerçekleştiği için aşağıdaki kutuya bakın) ve şifrelemeyle ilgili olarak medyadan alınan meta verileri (initData) içeren bir encrypted etkinliği tetikler.
  3. Uygulama, encrypted etkinliğini işler:
    1. Medya öğesiyle ilişkilendirilmiş bir MediaKeys nesnesi yoksa önce hangi Anahtar Sistemlerinin mevcut olduğunu kontrol etmek için navigator.requestMediaKeySystemAccess() öğesini kullanarak kullanılabilir bir Anahtar Sistemi seçin, ardından bir MediaKeySystemAccess nesnesi aracılığıyla kullanılabilir bir Anahtar Sistemi için MediaKeys nesnesi oluşturun. MediaKeys nesnesinin ilk encrypted etkinliğinden önce başlatılması gerektiğini unutmayın. Uygulama, lisans sunucusu URL'sini, kullanılabilir bir anahtar sisteminin seçilmesinden bağımsız olarak alır. MediaKeys nesnesi, bir işitsel veya video öğesinin medyasının şifresini çözmek için kullanılabilen tüm anahtarları temsil eder. Bir CDM örneğini temsil eder ve özellikle lisans sunucusundan anahtar almak için kullanılan anahtar oturumları oluşturmak amacıyla CDM'ye erişim sağlar.
    2. MediaKeys nesnesi oluşturulduktan sonra bunu medya öğesine atayın: setMediaKeys(), MediaKeys nesnesini bir HTMLMediaElement ile ilişkilendirir. Böylece, tuşları oynatma sırasında, yani kod çözme işlemi sırasında kullanılabilir.
  4. Uygulama, MediaKeys üzerinde createSession()'i çağırarak bir MediaKeySession oluşturur. Bu işlem, bir lisansın ve anahtarlarının kullanım süresini temsil eden bir MediaKeySession oluşturur.
  5. Uygulama, encrypted işleyicisinde elde edilen medya verilerini CDM'ye ileterek ve MediaKeySession üzerinde generateRequest()'yi çağırarak lisans isteği oluşturur.
  6. CDM, bir lisans sunucusundan anahtar edinme isteği olan bir message etkinliği tetikler.
  7. MediaKeySession nesnesi message etkinliğini alır ve uygulama lisans sunucusuna bir mesaj gönderir (ör. XHR aracılığıyla).
  8. Uygulama, lisans sunucusundan bir yanıt alır ve verileri MediaKeySession sınıfının update() yöntemini kullanarak CDM'ye iletir.
  9. CDM, lisanstaki anahtarları kullanarak medyanın şifresini çözer. Medya öğesiyle ilişkili MediaKey öğelerindeki herhangi bir oturumdan geçerli bir anahtar kullanılabilir. CDM, anahtar kimliğine göre dizine eklenen anahtara ve politikaya erişir.
  10. Medya oynatmaya devam edilir.

Vay canına…

CDM ile lisans sunucusu arasında birden fazla mesaj olabileceğini ve bu süreçteki tüm iletişimin tarayıcı ve uygulama tarafından anlaşılamadığını unutmayın: Mesajlar yalnızca CDM ve lisans sunucusu tarafından anlaşılır. Ancak uygulama katmanı, CDM'nin ne tür bir mesaj gönderdiğini görebilir. Lisans isteği, CDM'nin geçerliliğinin (ve güven ilişkisinin) kanıtını ve elde edilen lisanstaki içerik anahtarlarını şifrelemek için kullanılacak bir anahtarı içerir.

Peki CDM'ler aslında ne işe yarar?

EME uygulaması, medya şifresinin çözülmesi için tek başına bir yöntem sağlamaz. Yalnızca bir web uygulamasının İçerik Şifre Çözme Modülleri ile etkileşim kurması için bir API sağlar.

CDM'lerin gerçekte ne yaptığı EME spesifikasyonu tarafından tanımlanmaz. CDM'ler, şifre çözmenin yanı sıra medyanın kodunu çözme (sıkıştırmayı açma) işlemini de yapabilir. CDM işlevselliği için en azdan en sağlama doğru birkaç olası seçenek vardır:

  • Yalnızca şifre çözme. Örneğin, <video> öğesi aracılığıyla normal medya ardışık düzenini kullanarak oynatmayı etkinleştirir.
  • Şifre çözme ve kod çözme, video karelerini oluşturma için tarayıcıya iletme.
  • Şifre çözme ve kod çözme, doğrudan donanımda (ör. GPU) oluşturma.

Bir CDM'yi web uygulamasına sunmanın birden fazla yolu vardır:

  • CDM'yi tarayıcıyla birleştirin.
  • CDM'yi ayrı olarak dağıtın.
  • İşletim sistemine bir CDM oluşturun.
  • Donanım yazılımına CDM ekleyin.
  • Donanıma CDM yerleştirme

CDM'nin nasıl kullanıma sunulacağı EME spesifikasyonunda tanımlanmaz ancak her durumda CDM'yi incelemekten ve göstermekten tarayıcı sorumludur.

EME, belirli bir anahtar sistemini zorunlu kılmaz. Mevcut masaüstü ve mobil tarayıcılar arasında Chrome, Widevine'i, IE11 ise PlayReady'yi destekler.

Lisans sunucusundan anahtar alma

Tipik ticari kullanımda içerik, bir paketleme hizmeti veya aracı kullanılarak şifrelenir ve kodlanır. Şifrelenmiş medya internette kullanıma sunulduktan sonra web istemcisi, lisans sunucusundan bir anahtar (lisans içinde bulunur) edinebilir ve içeriğin şifresini çözmek ve oynatmak için bu anahtarı kullanabilir.

Aşağıdaki kodda (özellik örneklerinden uyarlanmıştır), bir uygulamanın nasıl uygun bir anahtar sistemi seçebileceği ve lisans sunucusundan anahtar alabileceği gösterilmektedir.

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

Ortak Şifreleme

Ortak Şifreleme çözümleri, içerik sağlayıcıların içeriklerini kapsayıcı/kodek başına bir kez şifrelemelerine ve paketlemelerine ve çeşitli Anahtar Sistemleri, CDM'ler ve istemcilerle (yani Ortak Şifreleme'yi destekleyen tüm CDM'ler) kullanmalarına olanak tanır. Örneğin, PlayReady kullanılarak paketlenmiş bir video, Widevine lisans sunucusundan anahtar alan bir Widevine CDM kullanılarak tarayıcıda oynatılabilir.

Bu, genellikle uygulama çalışma zamanı da içeren tek bir istemci de dahil olmak üzere yalnızca tam bir dikey yığınla çalışacak eski çözümlerin aksinedir.

Ortak Şifreleme (CENC), ISO BMFF için koruma şeması tanımlayan bir ISO standardıdır. Benzer bir kavram WebM için de geçerlidir.

Anahtarı temizle

EME, DRM işlevini tanımlamasa da spesifikasyon şu anda EME'yi destekleyen tüm tarayıcıların Clear Key'i uygulaması gerektiğini zorunlu kılmaktadır. Bu sistem sayesinde medya bir anahtarla şifrelenip anahtar sağlanarak oynatılabilir. Anahtarı Temizle, tarayıcıda yerleşik olarak bulunabilir: Ayrı bir şifre çözme modülünün kullanılmasını gerektirmez.

Birçok ticari içerik türü için kullanılması olası olmasa da Clear Key, EME'yi destekleyen tüm tarayıcılarda tam olarak birlikte çalışabilir. Ayrıca, lisans sunucusundan içerik anahtarı istemek zorunda kalmadan EME uygulamalarını ve EME kullanan uygulamaları test etmek için de kullanışlıdır. simpl.info/ck adresinde basit bir Clear Key örneği verilmiştir. Aşağıda, lisans sunucusu etkileşimi olmasa da yukarıda açıklanan adımlara paralel olarak kodun bir adım adım açıklamalı kılavuzu verilmiştir.

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

Bu kodu test etmek için, oynatmak üzere şifrelenmiş bir videoya ihtiyacınız vardır. Bir videoyu Clear Key ile kullanmak üzere şifrelemek için WebM'de webm_crypt talimatlarına göre işlem yapabilirsiniz. Ticari hizmetler de mevcuttur (en azından ISO BMFF/MP4 için) ve diğer çözümler geliştirilmektedir.

Medya Kaynağı Uzantıları (MSE)

HTMLMediaElement, basit bir güzelliğe sahip bir öğedir.

Sadece bir src URL'si sağlayarak medyaları yükleyebilir, kodunu çözebilir ve oynatabiliriz:

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

Media Source API, JavaScript'in video "bölümlerinden" oynatma için akış oluşturmasına olanak tanıyarak medya kaynağı üzerinde daha ayrıntılı kontrol sağlayan HTMLMediaElement uzantısıdır. Bu da uyumlu akış ve zaman kaydırma gibi teknikleri mümkün kılar.

MSE, EME için neden önemlidir? Ticari içerik sağlayıcılar, korumalı içerik dağıtmanın yanı sıra içerik yayınlamayı ağ koşullarına ve diğer şartlara uyarlayabilmeleri gerekir. Örneğin Netflix, ağ koşulları değiştikçe akış bit hızını dinamik olarak değiştirir. EME, src özelliği aracılığıyla sağlanan medyayla olduğu gibi, MSE uygulaması tarafından sağlanan medya akışlarının oynatılmasıyla çalışır.

Farklı bit hızlarında kodlanmış medyayı nasıl parçalara ayırabilir ve oynatabilirim? Aşağıdaki DASH bölümüne bakın.

MSE'yi simpl.info/mse adresinde görebilirsiniz. Bu örnekte, bir WebM videosu File API'leri kullanılarak beş parçaya bölünmüştür. Bir üretim uygulamasında, video parçaları Ajax aracılığıyla alınır.

Öncelikle bir SourceBuffer oluşturulur:

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

Daha sonra filmin tamamı, her bir parçayı insertBuffer() yöntemi kullanılarak eklenerek bir video öğesine "akışır" hale gelir:

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 hakkında daha fazla bilgiyi HTML5 Rocks makalesinde bulabilirsiniz.

HTTP üzerinden Dinamik Adaptif Akış (DASH)

Çoklu cihaz, çoklu platform, mobil... Ne derseniz deyin, web genellikle değişken bağlantı koşullarında kullanılır. Dinamik, uyarlanabilir yayınlama, çoklu cihaz dünyasındaki bant genişliği kısıtlamaları ve değişkenlikle başa çıkmak için çok önemlidir.

DASH (MPEG-DASH olarak da bilinir), hem akış hem de indirme işlemleri için güvenilir olmayan bir ortamda mümkün olan en iyi medya yayınını sağlamak üzere tasarlanmıştır. Apple'ın HTTP Canlı Akışı (HLS) ve Microsoft'un Smooth Streaming gibi diğer bazı teknolojiler de benzer bir işlev sunar ancak DASH, açık bir standarda dayalı olan tek HTTP üzerinden uyarlanabilir bit hızı akış yöntemidir. DASH, YouTube gibi siteler tarafından zaten kullanılıyor.

Bunun EME ve MSE ile ne ilgisi var? MSE tabanlı DASH uygulamaları, mevcut HTTP altyapısını kullanarak bir manifest'i ayrıştırabilir, video segmentlerini uygun bit hızında indirebilir ve ihtiyaç duyduğunda bunları bir video öğesine besleyebilir.

Diğer bir deyişle DASH, ticari içerik sağlayıcıların korumalı içerikleri uyarlanabilir şekilde yayınlamasına olanak tanır.

DASH, adından da anlaşılacağı gibi şu özellikleri sunar:

  • Dinamik: Değişen koşullara tepki verir.
  • Uyarlanabilir: Uygun bir ses veya video bit hızı sağlamak için uyum sağlar.
  • Akış: İndirmenin yanı sıra canlı yayına da olanak tanır.
  • HTTP: Geleneksel bir akış sunucusunun dezavantajları olmadan HTTP'nin avantajlarıyla içerik yayınlamayı sağlar.

BBC, DASH kullanarak test akışları sağlamaya başladı:

Özetlemek gerekirse:

  1. Medya farklı bit hızlarında kodlanır.
  2. Farklı bit hızı dosyaları bir HTTP sunucusundan kullanılabilir hale getirilir.
  3. İstemci web uygulaması, DASH ile hangi bit hızının alınacağını ve oynatılacağını seçer.

Video segmentasyon sürecinin bir parçası olarak, medya sunum açıklaması (MPD) olarak bilinen bir XML manifesti programatik olarak oluşturulur. Bu, süreleri ve URL'leri içeren Uyarlama Kümeleri ve Temsilasyonları'nı açıklar. MPD şu şekilde görünür:

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

(Bu XML, YouTube DASH demo oynatıcısında kullanılan .mpd dosyasından alınmıştır.)

DASH spesifikasyonuna göre MPD dosyası teoride bir video için src olarak kullanılabilir. Ancak web geliştiricilerine daha fazla esneklik sağlamak için tarayıcı tedarikçileri, DASH desteğini dash.js gibi MSE kullanan JavaScript kitaplıklarına bırakmayı tercih etti. DASH'i JavaScript'de uygulamak, uyum algoritmasının tarayıcı güncellemeleri gerektirmeden gelişmesine olanak tanır. MSE'yi kullanmak, tarayıcı değişikliği gerektirmeden alternatif manifest biçimleri ve yayınlama mekanizmaları ile denemeler yapmaya da olanak tanır. Google'ın Shaka Player'ı, EME desteğine sahip bir DASH istemcisi uygular.

Mozilla Geliştirici Ağı'nda videoyu segmentlere ayırmak ve MPD oluşturmak için WebM araçları ve FFmpeg'in nasıl kullanılacağıyla ilgili talimatlar bulunmaktadır.

Sonuç

Ücretli video ve ses yayınlamak için web'in kullanımı çok hızlı bir şekilde artıyor. Tablet, oyun konsolu, bağlı TV veya set üstü kutu gibi yeni cihazların tümü, büyük içerik sağlayıcılardan HTTP üzerinden medya aktarabiliyor. Mobil ve masaüstü tarayıcıların %85'inden fazlası artık <video> ve <audio>'i destekliyor. Cisco, 2017'ye kadar videonun dünya genelindeki tüketici internet trafiğinin yüzde 80 ila 90'ını oluşturacağını tahmin ediyor. Bu bağlamda, tarayıcı tedarikçileri çoğu medya eklentisinin kullandığı API'ler için desteği azalttıkça, korunan içerik dağıtımı için tarayıcı desteğinin giderek daha önemli hale gelmesi muhtemeldir.

Daha fazla bilgi

Özellikler ve standartlar

Makaleler