EME WTF?

An introduction to Encrypted Media Extensions

HTML5 Rocks

Encrypted Media Extensions が提供するAPIにより、Webアプリケーションはコンテンツ保護システムとやりとりして、暗号化された音声や映像を再生することが可能になります。

この記事ではEME APIとその使い方を紹介します。EMEにまつわる対立に興味がある方は、ドキュメントに賛成/反対の議論を要約しましたのでそちらをご覧ください。

一般的なデジタルメディアの入門としては、Monty Montgomery の Digital Media Primer for Geeksをご覧ください。

EME は、すべてのブラウザにおいて、特定のコンテンツ保護システムに依存せず、同一のアプリケーションが、同一の暗号化されたファイルを再生できるように設計されています。前者はAPIとフローを標準化することにより可能になり、また、後者は Common Encryption の概念により可能になります。

EME は HTMLMediaElement の仕様の「拡張」であり、それが名前の由来となっています。「拡張」であるということは、ブラウザでのサポートは任意であることを意味します。つまり、サポートしていないブラウザは、暗号化されたメディアを再生できないというだけで、EMEはHTMLの仕様に準拠するにあたって必須ではありません。以下はEMEの仕様からの引用です:

この提案は HTMLMediaElement を拡張して保護されたコンテンツの再生を制御するAPIを提供するものです。

このAPIは、単純なClear Keyによる復号化から、高付加価値ビデオ (ユーザエージェントによる適切な実装が前提となる) まで、広範囲のユースケースをサポートします。ライセンスや鍵の交換をアプリケーションが制御することで、幅広いコンテンツ暗号/保護技術をサポートする、強力な再生アプリケーションの開発を促進します。

この仕様書はコンテンツ保護やDRMのシステムを定義するものではありません。そうではなく、そのようなシステムを、単純なコンテンツ暗号システムと同様、発見し、選び、対話するための、共通のAPIを定義するものです。DRMの実装は当該仕様に準拠するための必須条件ではありません。最低限の単純なClear Keyシステムの実装だけが要求されます。

このAPIは、コンテンツ保護の単純な機能を提供するだけで、認証や権限のようなアプリケーションの機能はページの作者に任されています。コンテンツ保護のシステムごとに異なる処理は、ページ側で実現されなければいけません。これにより、暗号化システムとライセンスサーバ間の外部通信を仮定せずに済みます。

EMEの実装は以下の外部コンポーネントを使用します。

  • 鍵システム: コンテンツ保護 (DRM) の仕組み。EME の仕様自体は鍵システムを定義しませんが、例外として、Clear Key (以下を参照) のみ定義します。
  • Content Decryption Module (CDM): 暗号化されたメディアの再生を行う、クライアントサイドのソフトウェアもしくはハードウェアのモジュール。鍵システムと同様、EME はCDMを定義せず、アプリケーションが利用可能なCDMと対話するためのインターフェイスのみを提供します。
  • ライセンス(鍵)サーバ: CDMと協調して復号化用の鍵を提供します。ライセンスサーバとの実際のやり取りはアプリケーションの責務となります。
  • パッケージングサービス: メディアをエンコード/暗号化して、実際に配布/消費可能な形にします。

EMEは復号化のためにライセンスサーバから取得した鍵を必要としますが、ユーザIDや認証はEMEの範疇ではないことに注意してください。メディア再生のための鍵の取得は、通常はユーザ認証の後に行われます。NetflixのようなサービスはWeb アプリケーション内でユーザ認証を行わなければいけません。すなわち、ユーザがログインしたときにアプリはユーザを特定し、権限を付与します。

EMEはどのように動作するか?

以下、EMEの各コンポーネントがどのように相互作用するか記します。ちなみにこれは、下のコード例に対応しています。

  1. Webアプリケーションは、暗号化されたストリームを含むオーディオもしくはビデオを再生しようとします。
  2. ブラウザはメディアデータが暗号化されている事を察知し、(なぜそれが可能か、下欄に説明があります。) needkey イベントを発行します。イベントには、メディアから取得した暗号化に関する情報 (initData) が添付されます。
  3. アプリケーションはneedkeyイベントを以下の手順で処理します。
    1. Media 要素に MediaKeys オブジェクトが関連づけられていない場合、利用可能な鍵システムおよびライセンスサーバのURLを設定します。MediaKeys.isTypeSupported()を使用することで、どの鍵システムが利用可能か調べることができます。そして、その鍵システムのMediaKeysオブジェクトを作成します。MediaKeysオブジェクトはaudioもしくはvideo要素においてメディアデータの復号化に使用される鍵を表します。それはCDMインスタンスを表し、CDMへのアクセス手段 (特に鍵セッションの作成) を提供します。
    2. 作成したMediaKeysオブジェクトをMedia要素にセットします。setMediaKeys()メソッドにより、MediaKeysオブジェクトと HTMLMediaElement が関連づけられます。以降は再生中、つまりデコードしている間、その鍵が使用されます。
  4. アプリケーションはneedkeyのイベントハンドラで取得したメディアデータをCDMに渡します。これはMediaKeysオブジェクトのcreateSession()メソッドを呼び出すことで行います。これにより、MediaKeySessionオブジェクトが作成されます。このオブジェクトはライセンスおよび鍵の存続期間を表します。
  5. CDMはmessageイベントを発行し、ライセンスサーバから鍵を取得することを要求します。
  6. MediaKeySessionオブジェクトはmessageイベントを受信するので、アプリケーションはライセンスサーバに (XHR経由等の手段で) メッセージ送信します。
  7. ライセンスサーバからレスポンス取得すると、アプリケーションはそのデータをCDMに渡します。これは、MediaKeySessionオブジェクトのupdate()メソッドを呼び出すことで行います。
  8. CDMはライセンス鍵を使ってメディアデータを復号化します。有効な鍵は、Media要素に関連づけられたMediaKeyオブジェクト内のいずれのセッションからも使用されます。鍵は鍵IDにより特定され、CDMは鍵と関連するデータを鍵IDごとに保持します。
  9. ようやくメディアの再生がはじまります。

(;´Д`)=3

どのようにしてブラウザはメディアが暗号化されていることを察知するか?

この情報は ISO BMFFWebM のようなメディアコンテナファイルの中にメタデータとして存在します。ISO BMFFの場合、ヘッダー内の protection scheme information box がこれにあたります。WebMは、Matroskaの ContentEncryption element にWebM固有の情報を追加して使用しています。各コンテナフォーマットにおけるガイドラインに関してEMEの仕様を参照ください。

CDMとサーバの間で複数のメッセージがやりとりされるかもしれませんが、これらの通信はブラウザやアプリケーションには不過視となっており、CDMとライセンスサーバだけがメッセージを解します。ライセンスのリクエストはCDMの正当性と信頼関係を証明するためのデータを含みます。また、ライセンス鍵のデータを暗号化する際に使用する鍵も含みます。

・・で、CDMは実際には何をしてるの?

EMEの実装は、単にアプリケーションがContent Decryption Modules とやりとりするためのAPIを提供するだけで、それ自身はメディア復号化の機能を提供しません。

EME の仕様には、CDM が実際に何をするかについて定義されていません。また、CDMはメディアの復号化だけでなく、デコード(展開)も行う場合があります。CDMの提供する機能については、最小限のものから、強力なものまで、幾通りもの選択肢が考えられます。

  • 復号化のみ行う。通常のメディアパイプライン、例えば <video> 要素を使って再生する。
  • 復号化とデコードを行う。できあがったビデオフレームをブラウザに渡して描画してもらう。
  • 復号化とデコードを行う。そのままGPU等のハードウェアで描画する。

CDM をWeb アプリケーションから利用可能にするには、いくつかの方法があります。

  • CDM をブラウザに同梱する。
  • CDM を別途配布する。
  • CDM をOSの一部として提供する。
  • ファームウェアにCDM が搭載されている。
  • CDM がハードウェアとして提供される。

どうやってCDMを利用可能にするかについて、EME の仕様には定義されていません。しかし、いずれの場合もブラウザが責任を持ってCDM を提供します。

EME は特定の鍵システムを必須条件としません。今日のデスクトップおよびモバイルのブラウザにおいては、Chrome は Widevine を、また IE11 は PlayReady をサポートしています。

ライセンスサーバから鍵を取得する

多くの商用サービスでは、コンテンツは何らかのパッケージングサービスあるいはツールを用いて暗号化および圧縮されます。そして、ひとたび暗号化されたメディアがオンラインで利用可能になると、Web クライアントはライセンスサーバから鍵(ライセンス)を取得し、それによりコンテンツを複合化して再生します。

以下のコードは仕様のExamplesの章からの抜粋です。アプリケーションが適切な鍵システムを選択し、ライセンスサーバから鍵を取得するやり方が書かれています。

<script>
var keySystem;
var licenseUrl;

function selectKeySystem() {
  if (MediaKeys.isTypeSupported("com.example.somesystem",
      "video/webm; codecs='vp8, vorbis'")) {
    licenseUrl = "https://license.example.com/getkey";
    keySystem = "com.example.somesystem";
  } else if (MediaKeys.isTypeSupported("com.foobar",
      "video/webm; codecs='vp8, vorbis'")) {
    licenseUrl = "https://license.foobar.com/request";
    keySystem = "com.foobar";
  } else {
    throw "Key System not supported";
  }
}

function handleKeyNeeded(event) {
  var video = event.target;
  if (!video.mediaKeys) {
    selectKeySystem();
    video.setMediaKeys(new MediaKeys(keySystem));
  }
  if (!video.mediaKeys) {
    throw "Could not create MediaKeys";
  }
  var keySession = video.mediaKeys.createSession(event.contentType, event.initData);
  if (!keySession) {
    throw "Could not create key session";
  }
  keySession.addEventListener("message", licenseRequestReady, false);
}

function licenseRequestReady(event) {
  var keySession = event.target;
  var request = event.message;
  if (!request) {
    throw "Could not create license request";
  }
  var xmlhttp = new XMLHttpRequest();
  xmlhttp.open("POST", licenseUrl);
  xmlhttp.onreadystatechange = function () {
    if (xmlhttp.readyState === 4) {
      var license = new Uint8Array(xmlhttp.response);
      keySession.update(license); // playback can now begin
    }
  }
  xmlhttp.send(request);
}
</script>

...

<video src="foo.webm" autoplay onneedkey="handleKeyNeeded(event)"></video>

Common Encryption

Common Encryption により、コンテンツプロバイダーは、ひとつのコンテナーフォーマット/コーデックに対して一回のみ暗号化とパッケージングを行うだけでよくなります。そして、それは様々な鍵システムおよびCDM (Common Encryptionに対応したCDM)間で使い回すことができます。例えば、PlayReadyでパッケージングされたビデオはWidevineのCDMを使ったブラウザで、Widevineのライセンスサーバから鍵を取得して再生することが可能です。

それに比べて従来の方式では、ソフトウェアスタックが完全に縦割りになっているので、単一のクライアント(多くの場合アプリケーション・ランタイム)でしか動作しません。

CENC は Common Encryption の ISO BMFF 標準であり、類似の考え方が WebM においても適用されています。

Clear Key

EME はDRM の機能を規定しませんが、現時点の仕様によれば、すべてのEME 準拠のブラウザはClear Keyを実装しなければいけません。このシステムでは、単純にメディアを暗号化した鍵をそのまま再生に使用します。Clear Keyはブラウザのみで実装され、別途 CDM を必要としません。

多くの商用コンテンツでは使われないでしょうが、Clear Key はすべてのEME 準拠ブラウザで完全に相互運用可能です。また、EME の実装をテストする場合や、EME を使用するアプリケーションをテストする場合などに、ライセンスサーバを立てる必要がないので便利です。簡単なClear Key の実装例が simpl.info/clearkey にあります。下にコードを詳しく解説しています。上のコード例と似ていますが、ライセンスサーバとのやりとりが無いところが違います。(このコードはEME のEditor's Draft版である プリフィックスバージョン 0.1b に対応しており、最新のChromeで実装されています。)

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

// Specify the Key System used: in this example, Clear Key
var keySystem = 'webkit-org.w3.clearkey';

// Add listeners to the media element
var videoElement = document.querySelector('video');
videoElement.addEventListener('needkey', onNeedKey);
videoElement.addEventListener('keymessage', onKeyMessage);
videoElement.addEventListener('keyerror', onKeyError);
videoElement.addEventListener('keyadded', onKeyAdded);

// Handle the needkey event
function onNeedKey(e) {
  // Generate a key request, specifying the Key System and media InitData
  // e.target is the video
  e.target.webkitGenerateKeyRequest(keySystem, e.initData);
}

// Handle a key message, adding a key
function onKeyMessage(e) {
  var initData = e.message;
  e.target.webkitAddKey(keySystem, KEY, initData);
}

このコードをテストするためにはまず、ビデオを暗号化する必要があります。WebMの場合、Clear Keyでビデオを暗号化するにはwebm_crypt を使った手順を参照ください。商用サービスも (少なくともISO BMFF/MP4ならば) 存在しますし、その他のサービスも開発されています。

関連技術 その1

HTMLMediaElementはシンプルさが売りです。

src 属性に URLをセットするだけで、メディアのロード、デコードそして再生が可能です。

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

Media Source API は HTMLMediaElement の拡張で、メディアソースに対してさらにきめの細かい制御ができるようになります。これにより、JavaScriptで「チャンク」単位でビデオのストリームを扱うことができるようになり、その結果、アダプティブストリーミングやタイムシフト等の技術が可能になります。

なぜ MSE は EME にとって重要なのでしょうか? なぜなら、商用コンテンツのプロバイダーは、保護されたコンテンツの配信を行うだけでなく、ネットワークの状況やその他の要件に合わせてコンテンツの配信を調整しなければいけないからです。例えば、Netflix は、ネットワーク状況の変化に応じて、ストリームのビットレートを動的に変えています。src 属性により与えられたメディアと同様、EME は MSE の実装により与えられたメディアストリームの再生においても動作します。

異なるビットレートでエンコードされたメディアは、どのようにして分割/再生されるのでしょうか?以下のDASH の節をご覧ください。

実際に動作する MSE の例は、simpl.info/mse で見ることができます。 このデモでは、WebM ビデオは File API により、5 つのチャンクに分割されていますが、実際のアプリケーションでは、ビデオのチャンクは AJAX 経由で取得されるでしょう。

まず、SourceBuffer を作成します。

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

そして、video 要素に対してビデオを流し込みます。これには、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 の記事も併せてご覧ください。

関連技術 その2

マルチデバイス、マルチプラットフォーム、モバイル、呼び名はどうあれ、Web はしばしば不安定な接続の条件下で消費されます。そのようなマルチデバイスの世界では、帯域の制限や流動性に対処するために、動的でアダプティブな配信技術が不可欠です。

DASH (通称 MPEG-DASH) は不安定な状況でベストなメディア配信を実現するために設計されました。ストリーミングとダウンロード両方に対応しています。類似の技術は他にもたくさんあります。例えば、Apple の HTTP Live Streaming (HLS) や、Microsoft の Smooth Streaming です。しかし DASH は唯一オープンスタンダードに基づいた HTTP 上のアダプティブ・ビットレート・ストリーミングの方式です。DASH はすでに YouTube のようなサイトで実績があります。

では、これが EME および MSE とどう関係するのでしょうか?MSE ベースの DASH の実装は、マニフェストファイルをパースし、適切なビットレートのビデオの断片をダウンロードし、そして video 要素の消費スピードに合わせてそれらのデータを供給します。これらはすべて、既存のHTTPの基盤を利用して行われます。

別の言い方をすると、DASH により、商用コンテンツのプロバイダは、保護されたコンテンツをアダプティブストリーミングすることが可能になります。

DASH はその名の通り、

  • Dynamic: 変化する状況に対応します。
  • Adaptive: 最適なオーディオ/ビデオを提供するためにビットレートを調整します。
  • Streaming: ダウンロードと同様、ストリーミングも対応します。
  • HTTP: HTTP を利用したコンテンツ配信が可能となるため、従来のストリーミングサーバより便利です。

BBC は DASH を用いたテストストリームの配信を始めました。

メディアは複数の異なるビットレートでエンコードされます。エンコードされたものを Representation と呼びます。これはさらに複数の Media Segment に分割されます。クライアントは Representation の先頭から順に Media Segment をHTTPリクエストしてビデオを再生します。同一コンテンツの複数の Representation は Adaptation Set にグループ化されます。クライアントがビットレートを変更する場合、現在の Adaptation Set から代替の Representation を選び、Media Segment をリクエストします。クライアントがこのような変更を簡単に行えるように、コンテンツはエンコードされているのです。複数の Media Segment に加えて、通常 Representation は Initialisation Segment を保持します。これはヘッダーのようなもので、エンコーディングの情報やフレームサイズ等を含みます。クライアントは Media Segment を消費する前に、Representation からこのヘッダー情報を取得する必要があります。

まとめると、

  1. メディアは異なるビットレートでエンコードされます。
  2. 異なるビットレートのファイルはHTTPサーバにより提供されます。
  3. クライアント Web アプリケーションは DASH により、最適なビットレートを選択できます。

ビデオを分割する過程で、Media Presentation Description (MPD) と呼ばれる XML マニフェストファイルが自動的に生成されます。このファイルは Adaptation Set と Representation および、再生時間と 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 は YouTube DASH デモプレイヤー において使われている .mpd ファイルからの抜粋です。

DASH の仕様によれば、MPD ファイルは理論上は video 要素の src 属性として設定可能ですが、ブラウザベンダーはそうする代わりに、例えば dash.js のように、JavaScript ライブラリ側で MSE を用いて DASH サポートを行えるようにしました。そうすることで Web 開発者はより柔軟に対応できます。 DASH を JavaScript 側の実装に任せることにより、ブラウザを更新することなく、アダプテーションストリーミングのアルゴリズムを進化させることができます。また、MSE により、代替のマニフェストフォーマットや配信の仕組みを、ブラウザの変更無しに実験することができます。

Mozilla Developer Network に、WebM ツールと FFmpeg を用いてビデオを分割し、MPDを生成する手順についての記事があります。

結び

Web を使用した有料のビデオ/オーディオの配信は急激に成長しています。タブレット、ゲーム機、テレビ、STB等の、ほぼすべての新しいデバイスはメジャーなコンテンツプロバイダからHTTP 経由でメディアをストリーミング再生可能です。85% 以上のモバイルおよびデスクトップのブラウザは <video> と <audio> タグをサポートします。また、Cisco の試算によると、2017 年までに世界のコンシューマー・インターネットのトラフィックのうち、80 から 90 % をビデオが占めるようになるそうです。 この文脈において、ブラウザが保護されたコンテンツの配信をサポートすることの重要性は、ますます高まると思われます。ブラウザベンダーは、多くのメディアプラグインが依存している API のサポートを縮小していることですし。

参考文献

仕様と標準

記事

デモ

Comments

0