暗号化されたメディア拡張機能は、ウェブ アプリケーションがコンテンツ保護システムとやり取りして、暗号化された音声と動画の再生を可能にする 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() を使用して使用可能なキーシステムを確認して、使用可能なキーシステムの MediaKeys オブジェクトを MediaKeySystemAccess オブジェクト経由で作成します。MediaKeys オブジェクトの初期化は、最初の暗号化イベントの前に行う必要があります。ライセンス サーバー URL の取得は、利用可能な鍵システムの選択とは別にアプリによって行われます。MediaKeys オブジェクトは、音声要素または動画要素のメディアの復号に使用できるすべてのキーを表します。これは CDM インスタンスを表し、CDM へのアクセスを提供します。特に、ライセンス サーバーから鍵を取得するために使用される鍵セッションの作成に使用されます。
MediaKeys オブジェクトを作成したら、メディア要素に割り当てます。setMediaKeys() は、MediaKeys オブジェクトを HTMLMediaElement に関連付け、再生中(デコード中)に鍵を使用できるようにします。
アプリは、MediaKeys で createSession() を呼び出して MediaKeySession を作成します。これにより、ライセンスとそのキーの有効期間を表す MediaKeySession が作成されます。
アプリは、暗号化されたハンドラで取得したメディアデータを CDM に渡し、MediaKeySession で generateRequest() を呼び出して、ライセンス リクエストを生成します。
CDM は、ライセンス サーバーから鍵を取得するためのリクエストであるメッセージ イベントを発生させます。
MediaKeySession オブジェクトがメッセージ イベントを受信し、アプリが(XHR などを使用して)ライセンス サーバーにメッセージを送信します。
アプリはライセンス サーバーからレスポンスを受信し、MediaKeySession の update() メソッドを使用してデータを CDM に渡します。
CDM は、ライセンス内の鍵を使用してメディアを復号します。有効なキーは、メディア要素に関連付けられた MediaKeys 内の任意のセッションから使用できます。CDM は、Key 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 はブラウザに組み込むことができ、個別の復号モジュールを使用する必要はありません。
多くの種類の商用コンテンツには使用されませんが、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 はシンプルで美しいものです。
src 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 ファイルを動画の src として使用できます。ただし、ウェブ デベロッパーに柔軟性を提供するため、ブラウザ ベンダーは、代わりに MSE を使用する JavaScript ライブラリ(dash.js など)に 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 のブログ投稿
デモ
Clear Key デモ: simpl.info/ck Media Source Extensions(MSE)デモ Google の Shaka Player は、EME をサポートする DASH クライアントを実装しています