Encrypted Media Extensions は、ウェブ アプリケーションがコンテンツ保護システムとやり取りし、暗号化された音声と動画を再生できるようにする API を提供します。
EME は、基盤となる保護システムに関係なく、どのブラウザでも同じアプリと暗号化されたファイルを使用できるようにするように設計されています。前者は標準化された API とフローによって可能になり、後者は共通暗号化のコンセプトによって可能になります。
EME は、HTMLMediaElement の仕様の拡張で、名前の由来となっています。「拡張機能」は、ブラウザでの EME のサポートがオプションであることを意味します。暗号化されたメディアをサポートしていないブラウザでは、暗号化されたメディアを再生できませんが、HTML 仕様に準拠するうえで EME は必要ありません。EME 仕様より:
この提案は、保護されたコンテンツの再生を制御する API を提供する HTMLMediaElement を拡張したものです。
この API は、シンプルなクリアキーの復号から価値の高い動画(適切なユーザー エージェントの実装がある場合)まで、さまざまなユースケースに対応しています。ライセンス/鍵の交換はアプリによって制御されるため、さまざまなコンテンツの復号技術と保護技術をサポートする堅牢な再生アプリの開発が容易になります。
この仕様は、コンテンツ保護やデジタル著作権管理システムを定義するものではありません。そのようなシステムの検出、選択、操作、およびよりシンプルなコンテンツ暗号化システムとのやり取りに使用できる共通の API を定義します。この仕様に準拠するうえでデジタル著作権管理の実装は必須ではありません。共通ベースラインとして実装する必要があるのはクリアキー システムのみです。
この共通 API は、シンプルなコンテンツ暗号化機能セットをサポートしており、認証や認可などのアプリケーション機能はページ作成者に任せることができます。これは、暗号化システムとライセンスまたは他のサーバーとの間の帯域外通信を想定するのではなく、コンテンツ保護システム固有のメッセージをページによって仲介することを必須にすることで実現されます。
EME の実装では、次の外部コンポーネントを使用します。
- 鍵システム: コンテンツ保護(DRM)メカニズム。EME では、クリアキーを除き、鍵システム自体は定義されません(詳しくは下記をご覧ください)。
- コンテンツ復号モジュール(CDM): 暗号化されたメディアの再生を可能にするクライアント側のソフトウェアまたはハードウェアのメカニズム。キーシステムと同様に、EME でも CDM は定義されませんが、アプリが利用可能な CDM とやり取りするためのインターフェースを提供します。
- ライセンス(鍵)サーバー: CDM と連携して、メディアを復号するための鍵を提供します。ライセンス サーバーとのネゴシエーションはアプリが行います。
- パッケージング サービス: 配信や消費のためにメディアをエンコードおよび暗号化する。
EME を使用するアプリは、ライセンス サーバーとやり取りして復号に必要な鍵を取得しますが、ユーザー ID と認証は EME の一部ではありません。メディア再生を有効にするためのキーの取得は、(必要に応じて)ユーザーを認証した後に行われます。Netflix などのサービスは、ウェブ アプリケーション内でユーザーを認証する必要があります。ユーザーがアプリケーションにログインすると、アプリケーションがユーザーの ID と権限を判別します。
EME の仕組み
以下のコードサンプルに対応して、EME のコンポーネントがどのように相互作用するかを示します。
複数の形式またはコーデックを使用できる場合は、MediaSource.isTypeSupported() または HTMLMediaElement.canPlayType() の両方を使用して、適切なものを選択できます。ただし、CDM は、ブラウザが暗号化されていないコンテンツに対してサポートしているもののサブセットしかサポートしない場合があります。形式とコーデックを選択する前に MediaKeys の構成についてネゴシエートすることをおすすめします。アプリが暗号化されたイベントを待機しても、選択された形式/コーデックを処理できないことが MediaKeys に表示された場合は、再生を中断せずに切り替えるのに遅すぎる可能性があります。
まず、MediaKeysSystemAccess.getConfiguration() を使用して MediaKeys のネゴシエーションを行い、ネゴシエートされた構成を確認することをおすすめします。
選択できる形式/コーデックが 1 つしかない場合は、getConfiguration() は必要ありません。ただし、それでも最初に MediaKey を設定することをおすすめします。暗号化されたイベントを待機する理由は、コンテンツが暗号化されているかどうかを知る方法がない場合だけですが、実際にはその可能性は低くなります。
- ウェブ アプリケーションが、暗号化されたストリームを 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')
);
}
一般的な暗号化
共通暗号化ソリューションを使用すると、コンテンツ プロバイダは、コンテナ/コーデックごとにコンテンツを暗号化してパッケージ化し、さまざまな鍵システム、CDM、クライアント(共通暗号化をサポートするすべての CDM)で使用できます。たとえば、Playready を使用してパッケージ化された動画は、Widevine CDM を使用して Widevine ライセンス サーバーからキーを取得するブラウザ内で再生できます。
これは、アプリケーション ランタイムも含まれることが多い単一のクライアントなど、完全な垂直スタックでのみ機能する以前のソリューションとは対照的です。
Common Encryption(CENC)は、ISO BMFF の保護方式を定義する ISO 標準です。同様の概念が WebM にも適用されます。
キーを消去
EME では DRM 機能が定義されていませんが、現在の仕様では EME をサポートするすべてのブラウザでクリアキーを実装する必要があります。このシステムを使用すると、鍵でメディアを暗号化し、その鍵を提供するだけで再生できます。クリアキーはブラウザに組み込むことができます。個別の復号モジュールを使用する必要はありません。
Clear Key は、多くのタイプの商用コンテンツで使用される可能性は低いものの、EME をサポートするすべてのブラウザで完全に相互運用できます。また、ライセンス サーバーにコンテンツキーをリクエストせずに、EME の実装や EME を使用したアプリケーションのテストにも便利です。簡単なクリアキーの例が 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],
}),
);
}
このコードをテストするには、再生する動画を暗号化する必要があります。webm_crypt の手順に沿って、クリアキーで使用する動画を WebM で暗号化できます。商用サービスも利用でき(少なくとも ISO BMFF/MP4 に対応)、他のソリューションも開発中です。
関連技術 1: Media Source Extensions(MSE)
HTMLMediaElement は、シンプルな美しさを特徴とする生き物です。
src URL を指定するだけで、メディアの読み込み、デコード、再生ができます。
<video src="foo.webm"></video>
Media Source API は HTMLMediaElement の拡張機能であり、JavaScript が動画の「チャンク」から再生するためのストリームを作成できるようにすることで、メディアのソースをよりきめ細かく制御できます。これにより、アダプティブ ストリーミングやタイムシフトなどの手法が可能になります。
EME にとって MSE が重要な理由商用コンテンツ プロバイダは、保護されたコンテンツを配信するだけでなく、ネットワーク条件やその他の要件に合わせてコンテンツ配信を調整できる必要があるためです。たとえば 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 など、他のいくつかの技術でも同様の処理を行っていますが、DASH は、オープン スタンダードに基づく HTTP 経由のアダプティブ ビットレート ストリーミングを行う唯一の方法です。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 クライアントを実装します。
Mozilla Developer Network の説明では、WebM ツールと FFmpeg を使用して動画をセグメント化し、MPD を構築しています。
まとめ
有料の動画と音声を配信するウェブの利用は、急増しています。タブレット、ゲーム機、コネクテッド テレビ、セットトップ ボックスなど、新しいデバイスはすべて、主要なコンテンツ プロバイダからのメディアを 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 Test Streams: BBC R&D ブログ投稿
デモ
クリアキーのデモ: simpl.info/ck Media Source Extensions(MSE)デモ Google の Shaka Player は、EME をサポートする DASH クライアントを実装しています。