暗号化されたメディア拡張機能は、ウェブ アプリケーションがコンテンツ保護システムとやり取りして、暗号化された音声と動画の再生を可能にする API を提供します。
EME は、基盤となる保護システムに関係なく、どのブラウザでも同じアプリと暗号化されたファイルを使用できるように設計されています。前者は標準化された API とフローで実現され、後者は共通暗号化のコンセプトで実現されます。
EME は HTMLMediaElement 仕様の拡張機能であるため、そのように命名されています。「拡張機能」とは、ブラウザでの EME のサポートが任意であることを意味します。ブラウザが暗号化されたメディアをサポートしていない場合、暗号化されたメディアを再生することはできませんが、HTML 仕様に準拠するために EME は必要ありません。EME 仕様から:
このプロポーザルは HTMLMediaElement を拡張し、保護されたコンテンツの再生を制御するための API を提供します。
この API は、シンプルなクリアキーの復号から高価値の動画まで、さまざまなユースケースをサポートしています(適切なユーザー エージェント実装が前提)。ライセンスと鍵の交換はアプリによって制御されるため、さまざまなコンテンツの復号技術や保護技術をサポートする堅牢な再生アプリの開発が容易になります。
この仕様は、コンテンツ保護やデジタル著作権管理システムを定義するものではありません。むしろ、このようなシステムや、よりシンプルなコンテンツ暗号化システムの検出、選択、操作に使用できる共通の API を定義します。この仕様に準拠するためにデジタル著作権管理を実装する必要はありません。共通ベースラインとして実装する必要があるのは Clear Key システムのみです。
共通 API は、シンプルな一連のコンテンツ暗号化機能をサポートし、認証や認可などのアプリケーション機能をページ作成者に任せます。これは、暗号化システムとライセンスまたは他のサーバーとの間の帯域外通信を想定するのではなく、コンテンツ保護システム固有のメッセージのページによるメディエーションを要求することで実現しています。
EME 実装では、次の外部コンポーネントが使用されます。
- 鍵システム: コンテンツ保護(DRM)メカニズム。EME では、Clear Key を除き、鍵システム自体は定義されていません(詳しくは下記をご覧ください)。
- Content Decryption Module(CDM): 暗号化されたメディアの再生を可能にするクライアントサイドのソフトウェアまたはハードウェア メカニズム。鍵システムと同様に、EME は CDM を定義しませんが、利用可能な CDM とやり取りするためのインターフェースを提供します。
- ライセンス(鍵)サーバー: CDM とやり取りして、メディアの復号鍵を提供します。ライセンス サーバーとのネゴシエーションは、アプリケーションの責任で行う必要があります。
- パッケージング サービス: 配信 / 使用のためにメディアをエンコードして暗号化します。
EME を使用するアプリは、ライセンス サーバーとやり取りして鍵を取得し、復号を有効にしますが、ユーザー ID と認証は EME の一部ではありません。メディアの再生を可能にするためのキーの取得は、(必要に応じて)ユーザーの認証後に行われます。Netflix などのサービスは、ウェブ アプリケーション内でユーザーを認証する必要があります。ユーザーがアプリケーションにログインすると、アプリケーションはユーザーの ID と権限を決定します。
EME の仕組み
EME のコンポーネントがどのように連携するかは、以下のコード例に沿って説明します。
複数の形式またはコーデックを使用できる場合は、MediaSource.isTypeSupported() または HTMLMediaElement.canPlayType() の両方を使用して適切な形式を選択できます。ただし、CDM は、暗号化されていないコンテンツに対してブラウザがサポートしているもののサブセットのみをサポートする場合があります。形式とコーデックを選択する前に、MediaKeys 構成をネゴシエートすることをおすすめします。アプリケーションが暗号化されたイベントを待機しているときに、選択した形式/コーデックを処理できないと MediaKeys に表示された場合は、再生を中断せずに切り替えるのが遅すぎる可能性があります。
推奨されるフローは、最初に MediaKeys をネゴシエートし、MediaKeysSystemAccess.getConfiguration() を使用してネゴシエートされた構成を見つけることです。
選択できる形式/コーデックが 1 つしかない場合は、getConfiguration() は必要ありません。ただし、最初に MediaKeys を設定することをおすすめします。暗号化されたイベントを待つ唯一の理由は、コンテンツが暗号化されているかどうかを確認する方法がない場合ですが、実際にはその可能性はほとんどありません。
- ウェブ アプリケーションが、1 つ以上の暗号化されたストリームを含む音声または動画を再生しようとします。
- ブラウザはメディアが暗号化されていることを認識し(その仕組みについては下のボックスを参照)、暗号化に関するメディアから取得したメタデータ(initData)を含む暗号化イベントを発生させます。
アプリは暗号化されたイベントを処理します。
メディア要素に MediaKeys オブジェクトが関連付けられていない場合は、まず navigator.requestMediaKeySystemAccess() を使用して使用可能なキーシステムを選択し、使用可能なキーシステムを確認してから、MediaKeySystemAccess オブジェクトを使用して、使用可能なキーシステムの MediaKeys オブジェクトを作成します。MediaKeys オブジェクトの初期化は、最初の暗号化イベントの前に行う必要があります。ライセンス サーバー URL の取得は、利用可能な鍵システムの選択とは別にアプリによって行われます。MediaKeys オブジェクトは、音声要素または動画要素のメディアの復号に使用できるすべてのキーを表します。これは CDM インスタンスを表し、ライセンス サーバーから鍵を取得するために使用される鍵セッションの作成に、CDM へのアクセスを提供します。
MediaKeys オブジェクトを作成したら、メディア要素に割り当てます。setMediaKeys() は、MediaKeys オブジェクトを HTMLMediaElement に関連付け、再生中(デコード中)に鍵を使用できるようにします。
アプリは、MediaKeys で createSession() を呼び出して MediaKeySession を作成します。これにより、ライセンスとそのキーの有効期間を表す MediaKeySession が作成されます。
アプリは、MediaKeySession で generateRequest() を呼び出して、暗号化されたハンドラで取得したメディアデータを CDM に渡して、ライセンス リクエストを生成します。
CDM はメッセージ イベント(ライセンス サーバーからキーを取得するためのリクエスト)を発行します。
MediaKeySession オブジェクトがメッセージ イベントを受信し、アプリが(XHR などを使用して)ライセンス サーバーにメッセージを送信します。
アプリはライセンス サーバーからレスポンスを受信し、MediaKeySession の update() メソッドを使用してデータを CDM に渡します。
CDM は、ライセンス内の鍵を使用してメディアを復号します。有効なキーは、メディア要素に関連付けられた MediaKeys 内の任意のセッションから使用できます。CDM は、鍵 ID でインデックス付けされた鍵とポリシーにアクセスします。
メディアの再生が再開されました。
ブラウザはメディアが暗号化されていることをどのように認識しますか?
この情報は、ISO BMFF や WebM などの形式のメディア コンテナ ファイルのメタデータに格納されます。ISO BMFF の場合、これは保護スキーム情報ボックスと呼ばれるヘッダー メタデータです。WebM は Matroska ContentEncryption 要素を使用しますが、WebM 固有の追加機能もあります。ガイドラインは、EME 固有のレジストリ内の各コンテナに用意されています。
CDM とライセンス サーバーの間に複数のメッセージが存在する可能性があり、このプロセスでの通信はすべてブラウザとアプリに対して不透明です。メッセージは CDM とライセンス サーバーによってのみ認識されますが、アプリレイヤは CDM が送信するメッセージの種類を確認できます。ライセンス リクエストには、CDM の有効性(および信頼関係)の証明と、生成されるライセンス内のコンテンツ鍵を暗号化する際に使用する鍵が含まれています。
CDM は実際に何をするのでしょうか?
EME の実装自体には、メディアを復号する方法は用意されていません。ウェブ アプリケーションがコンテンツ復号モジュールを操作するための API が用意されているだけです。
CDM が実際に行う処理は EME 仕様で定義されていません。CDM は、復号だけでなくメディアのデコード(解凍)も処理できます。CDM 機能には、堅牢性の低いものから高いものにいくつかのオプションがあります。
- 復号のみ。<video> 要素など、通常のメディア パイプラインを使用して再生できます。
- 復号とデコード、レンダリング用に動画フレームをブラウザに渡す。
- 復号とデコード、ハードウェア(GPU など)での直接レンダリング。
CDM をウェブアプリで利用できるようにする方法は複数あります。
- CDM をブラウザにバンドルする。
- CDM を個別に配布する。
- オペレーティング システムに CDM をビルドします。
- ファームウェアに CDM を含める。
- CDM をハードウェアに埋め込む。
CDM を公開する方法は EME 仕様で定義されていませんが、すべての場合において、CDM の審査と公開はブラウザの責任となります。
EME では特定のキーシステムが義務付けられていません。現在のデスクトップ ブラウザとモバイル ブラウザでは、Chrome が Widevine をサポートし、IE11 が PlayReady をサポートしています。
ライセンス サーバーからキーを取得する
一般的な商用利用では、コンテンツはパッケージング サービスまたはツールを使用して暗号化され、エンコードされます。暗号化されたメディアがオンラインで利用できるようになると、ウェブ クライアントはライセンス サーバーから鍵(ライセンスに含まれる)を取得し、その鍵を使用してコンテンツの復号と再生が可能になります。
次のコード(仕様の例から応用)は、アプリが適切な鍵システムを選択し、ライセンス サーバーから鍵を取得する方法を示しています。
var video = document.querySelector('video');
var config = [{initDataTypes: ['webm'],
videoCapabilities: [{contentType: 'video/webm; codecs="vp09.00.10.08"'}]}];
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')
);
}
共通の暗号化
共通暗号化ソリューションを使用すると、コンテンツ プロバイダはコンテナ / コーデックごとに 1 回コンテンツを暗号化してパッケージ化し、さまざまな鍵システム、CDM、クライアント(つまり、共通暗号化をサポートする CDM)で使用できます。たとえば、Playready を使用してパッケージ化された動画は、Widevine ライセンス サーバーから鍵を取得する Widevine CDM を使用してブラウザで再生できます。
これは、アプリケーションのランタイムも含まれることが多い単一のクライアントを含む、完全な垂直スタックでのみ機能する以前のソリューションとは対照的です。
Common Encryption(CENC)は、ISO BMFF の保護スキームを定義する ISO 規格です。同様の概念が WebM にも当てはまります。
クリアキー
EME は DRM 機能を定義していませんが、現在の仕様では、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_crypt の手順に沿って WebM で行うことができます。商用サービス(少なくとも ISO BMFF/MP4)も利用可能で、他のソリューションも開発中です。
関連技術 1: Media Source Extensions(MSE)
HTMLMediaElement はシンプルで美しいものです。
ソース URL を指定するだけで、メディアの読み込み、デコード、再生ができます。
<video src="foo.webm"></video>
Media Source API は HTMLMediaElement の拡張機能で、JavaScript が動画の「チャンク」から再生するためのストリームを構築できるようにすることで、メディアのソースをよりきめ細かく制御できます。これにより、アダプティブ ストリーミングやタイムシフトなどの手法が可能になります。
MSE が EME にとって重要な理由商用コンテンツ プロバイダは、保護されたコンテンツの配信に加えて、ネットワーク条件やその他の要件にコンテンツ配信を適応させることができなければなりません。たとえば、Netflix はネットワークの状態に応じてストリーミング ビットレートを動的に変更します。EME は、src 属性で提供されるメディアと同様に、MSE 実装によって提供されるメディア ストリームの再生で機能します。
異なるビットレートでエンコードされたメディアをチャンク化して再生するにはどうすればよいですか?下記の DASH セクションをご覧ください。
MSE の動作は simpl.info/mse で確認できます。この例では、File API を使用して WebM 動画を 5 つのチャンクに分割します。本番環境のアプリケーションでは、動画のチャンクは 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 の詳細については、MSE の概要をご覧ください。
関連テクノロジー 2: Dynamic Adaptive Streaming over HTTP(DASH)
マルチデバイス、マルチプラットフォーム、モバイルなど、ウェブは接続が変化する状況で使用されることがよくあります。マルチデバイスの世界で帯域幅の制約とばらつきに対処するには、動的でアダプティブな配信が不可欠です。
DASH(MPEG-DASH)は、ストリーミングとダウンロードの両方で、不安定な環境で可能な限り最適なメディア配信を可能にするように設計されています。Apple の HTTP Live Streaming(HLS)や Microsoft の Smooth Streaming など、同様の機能を提供する技術は他にもありますが、HTTP を介したアダプティブ ビットレート ストリーミングでオープン標準に基づく唯一の方法は DASH です。DASH は、YouTube などのサイトですでに使用されています。
これは EME と MSE とどう関係していますか?MSE ベースの DASH 実装では、既存の HTTP インフラストラクチャを使用して、マニフェストを解析し、適切なビットレートで動画のセグメントをダウンロードし、空になったときに動画要素にフィードできます。
つまり、DASH を使用すると、商用コンテンツ プロバイダは保護されたコンテンツをアダプティブ ストリーミングできます。
DASH は、その名の通り、次の機能を備えています。
- 動的: 変化する状況に対応します。
- アダプティブ: 適切な音声または動画ビットレートを提供するように適応します。
- ストリーミング: ストリーミングとダウンロードが可能です。
- HTTP: 従来のストリーミング サーバーの欠点がなく、HTTP の利点を活かしてコンテンツ配信できます。
BBC は、DASH を使用したテスト ストリームの提供を開始しました。
メディアがさまざまなビットレートで何度もエンコードされている。各エンコードは表現と呼ばれますこれらは複数のメディア セグメントに分割されます。クライアントは、HTTP 経由で表現からセグメントを順番にリクエストして、番組を再生します。表現は、同等のコンテンツを含む表現の適応セットにグループ化できます。クライアントがビットレートを変更する場合は、現在の適応セットから代替を選択して、その表現からセグメントのリクエストを開始できます。コンテンツは、クライアントがこの切り替えを簡単に行えるようにする方法でエンコードされます。複数のメディア セグメントに加えて、表現には通常、初期化セグメントもあります。これは、エンコード、フレームサイズなどの情報が含まれるヘッダーと考えることができます。クライアントは、その表現からメディア セグメントを使用する前に、特定の表現についてこれを取得する必要があります。
まとめ
- メディアが異なるビットレートでエンコードされている。
- さまざまなビットレートのファイルは HTTP サーバーから利用できます。
- クライアント ウェブアプリは、DASH で取得して再生するビットレートを指定します。
動画セグメンテーション プロセスの一環として、Media Presentation Description(MPD)と呼ばれる XML マニフェストがプログラムで作成されます。これには、アダプテーション セットと表現が、長さと 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 ファイルは理論上は動画のソースとして使用できます。ただし、ウェブ デベロッパーに柔軟性を持たせるために、ブラウザ ベンダーは、dash.js などの MSE を使用する JavaScript ライブラリに DASH のサポートを任せることにしました。JavaScript で DASH を実装すると、ブラウザを更新しなくても適応アルゴリズムを進化させることができます。MSE を使用すると、ブラウザを変更しなくても、別のマニフェスト形式や配信メカニズムを試すことができます。Google の Shaka Player は、EME をサポートする DASH クライアントを実装しています。
WebM ツールと FFmpeg を使用して動画をセグメント化し、MPD を作成する方法については、Mozilla Developer Network の手順をご覧ください。
まとめ
ウェブを介した有料動画や有料音声の配信は、急速に拡大しています。タブレット、ゲーム機、コネクテッド テレビ、セットトップ ボックスなど、新しいデバイスはすべて、主要なコンテンツ プロバイダから HTTP 経由でメディアをストリーミングできるようです。現在、モバイルおよびパソコンのブラウザの 85% 以上が <video> と <audio> をサポートしています。Cisco は、2017 年までに世界の消費者インターネット トラフィックの 80 ~ 90% が動画が占めると予測しています。この状況において、ほとんどのメディア プラグインが依存する API のブラウザ ベンダーによるサポートの制限が進むにつれ、保護されたコンテンツ配信に対するブラウザのサポートの重要性が高まっていくと考えられます。
関連情報
仕様と標準
EME 仕様: 最新の編集者ドラフト Common Encryption(CENC) Media Source Extensions: 最新の編集者ドラフト DASH 標準(PDF) DASH 標準の概要
記事
DTG ウェビナー(一部古い) EME とは(Henri Sivonen 著) Media Source Extensions の概要 MPEG-DASH テスト ストリーム: BBC R&D のブログ投稿
デモ
クリアキーのデモ: simpl.info/ck Media Source Extensions(MSE)のデモ Google の Shaka Player は、EME をサポートする DASH クライアントを実装しています