EME 搞什麼?

Encrypted Media Extensions 簡介

Encrypted Media Extensions 提供 API,可讓網頁應用程式與內容保護系統互動,以播放加密的音訊和影片。

EME 的設計,無論底層保護系統為何,都能在各種瀏覽器中使用相同的應用程式和加密檔案。前者可透過標準化 API 和流程開發,後者則由「通用加密」的概念實現。

EME 是 HTMLMediaElement 規格的延伸,因此為名稱。「擴充功能」表示您可以自行決定是否要瀏覽器支援 EME:如果瀏覽器不支援加密媒體,就無法播放加密媒體,但遵循 HTML 規格要求 EME。在 EME 規格中:

EME 實作會使用下列外部元件:

  • 金鑰系統:內容保護 (DRM) 機制。除了「Clear Key」之外,EME 並未自行定義主要系統 (詳情請參閱下文)。
  • 內容解密模組 (CDM):可播放加密媒體的用戶端軟體或硬體機制。和 Key Systems 一樣,EME 不會定義任何 CDM,而是為應用程式提供與可用的 CDM 互動的介面。
  • 授權 (金鑰) 伺服器:與 CDM 互動,提供將媒體解密的金鑰。應用程式應負責與授權伺服器協商。
  • 封裝服務:對媒體進行編碼並加密,以便發布/消費。

請注意,使用 EME 的應用程式會與授權伺服器互動,以取得啟用解密功能的金鑰,但使用者身分和驗證機制不屬於 EME。(選擇性) 驗證使用者後,擷取金鑰以啟用媒體播放。Netflix 等服務必須在其網頁應用程式中驗證使用者:當使用者登入應用程式時,應用程式會判斷使用者身分和權限。

EME 如何運作?

以下是 EME 各元件的互動方式 (對應以下程式碼範例):

  1. 網頁應用程式嘗試播放含有一或多個加密串流的音訊或視訊。
  2. 瀏覽器會辨識媒體已加密 (具體情形請見下方的方塊),並會觸發 encrypted 事件,內含從加密相關媒體取得的中繼資料 (initData)。
  3. 應用程式處理 encrypted 事件:
    1. 如果沒有任何 MediaKeys 物件與媒體元素建立關聯,請先使用 navigator.requestMediaKeySystemAccess() 選取可用的金鑰系統,以查看可用的 Key Systems,然後透過 MediaKeySystemAccess 物件為可用的金鑰系統建立 MediaKeys 物件。請注意,MediaKeys 物件的初始化作業應在第一個 encrypted 事件之前發生。應用程式會自行取得授權伺服器網址,不會選取可用金鑰系統。MediaKeys 物件代表所有可將音訊或影片元素媒體解密時可用的金鑰。它代表 CDM 執行個體,並提供 CDM 的存取權,專門用於建立關鍵工作階段,可用來從授權伺服器取得金鑰。
    2. 建立 MediaKeys 物件後,請將其指派給媒體元素:setMediaKeys() 會將 MediaKeys 物件與 HTMLMediaElement 建立關聯,以便在播放期間使用其鍵,也就是解碼期間。
  4. 應用程式會在 MediaKeys 上呼叫 createSession() 來建立 MediaKeySession。這會建立 MediaKeySession,代表授權的生命週期及其金鑰。
  5. 應用程式會在 MediaKeySession 上呼叫 generateRequest(),將從 encrypted 處理常式取得的媒體資料傳遞至 CDM,藉此產生授權要求。
  6. CDM 會觸發 message 事件:要求從授權伺服器取得金鑰。
  7. MediaKeySession 物件接收 message 事件,而應用程式會將訊息傳送至授權伺服器 (例如透過 XHR)。
  8. 應用程式會接收來自授權伺服器的回應,並使用 MediaKeySessionupdate() 方法將資料傳遞至 CDM。
  9. CDM 會使用授權中的金鑰解密媒體。媒體元素相關聯的 MediaKey 內任何工作階段都可以使用有效的金鑰。CDM 會存取由金鑰 ID 建立索引的金鑰和政策。
  10. 繼續播放媒體。

呼...

請注意,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="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')
  );
}

常見的加密機制

常見的加密解決方案可讓內容供應者為每個容器/轉碼器執行一次內容加密及封裝,然後與各種金鑰系統、CDM 和用戶端 (也就是任何支援常見加密的 CDM) 搭配使用。舉例來說,只要使用 Widevine CDM 從 Widevine 授權伺服器取得金鑰,即可在瀏覽器中播放使用 PlayReady 的影片。

相較之下,舊版解決方案只適用於完整的垂直堆疊,包括通常包含應用程式執行階段的單一用戶端。

Common Encryption (CENC) 是定義 ISO BMFF 的 ISO 標準,類似概念也適用於 WebM。

清除金鑰

雖然 EME 未定義 DRM 功能,但規格目前要求所有支援 EME 的瀏覽器都必須執行 Clear Key。透過這個系統,系統可以使用金鑰將媒體加密,只要提供金鑰即可播放。瀏覽器內建 Clear Key 技術,無須使用獨立的解密模組。

雖然可能不適合用於多種商業內容,但 Clear Key 可以在所有支援 EME 的瀏覽器上完全互通。這也有助於測試 EME 實作項目,以及使用 EME 的應用程式,而不必從授權伺服器要求內容金鑰。simpl.info/ck 提供了簡單的 Clear Key 範例。下方是程式碼的逐步介紹,此程式碼與上述步驟平行,但沒有授權伺服器互動。

// 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 操作說明,為採用 Clear Key 的影片加密,以便透過 WebM 使用。可使用商業服務 (至少適用於 ISO BMFF/MP4) 和其他解決方案正在開發中。

媒體來源擴充功能 (MSE)

HTMLMediaElement 是簡單美妝的一種動物。

我們只需提供 src 網址,即可載入、解碼及播放媒體:

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

Media Source API 是 HTMLMediaElement 的擴充功能,允許 JavaScript 建立從影片區塊播放的串流,讓您更精細地控制媒體來源。進而推動自動調整串流與時間轉移等技巧。

為什麼 MSE 對 EME 如此重要?因為除了分發受保護內容外,商業內容供應者還需要能根據網路狀況和其他規定來調整內容傳遞。舉例來說,Netflix 會在網路條件改變時動態變更串流位元率。EME 處理 MSE 實作項目提供的媒體串流播放,就像透過 src 屬性提供的媒體一樣。

如何切割並播放不同位元率的媒體?請參閱下方的 DASH 部分。

您可以在 simpl.info/mse 查看 MSE 的實際運作情形;在本範例中,WebM 影片使用 File API 分成五個區塊。在產品應用程式中,系統會透過 Ajax 擷取影片區塊。

首先建立 SourceBuffer:

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

然後,系統就會透過 addBuffer() 方法附加每個區塊,將整部電影「串流」到影片元素:

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 岩石文章

HTTP 上的動態自動調整串流 (DASH)

涵蓋多種裝置、多平台、行動裝置 - 不管您稱呼它,網路在可變更的連線狀況下經常會發生。動態的自動調整式提供功能,對於因應多裝置時代的頻寬限制和變化性而言相當重要。

DASH (又稱 MPEG-DASH) 能在不穩定的環境中提供最佳媒體傳遞服務,同時適用於串流和下載作業。許多其他技術的功能類似,例如 Apple 的 HTTP 即時串流 (HLS) 和 Microsoft 的 Smooth Streaming (Microsoft 的流暢串流),但 DASH 是只能透過 HTTP 自動調整位元率串流的唯一方法,且採用公開標準。DASH 已由 YouTube 等網站使用。

與 EME 和 MSE 之間有什麼關係?以 MSE 為基礎的 DASH 實作項目可剖析資訊清單、以適當的位元率下載影片片段,並在飢餓時將片段提供給影片元素 (使用現有的 HTTP 基礎架構)。

換句話說,DASH 可讓商業內容供應者自動串流播放受保護的內容。

DASH 會處理錫在錫礦上說的內容:

  • 動態:回應不斷變化的條件。
  • 自動調整:自動調整,提供適當的音訊或視訊位元率。
  • 串流:允許串流播放和下載。
  • HTTP:利用 HTTP 進行內容傳遞,不具備傳統串流伺服器的優點。

BBC 已開始使用 DASH 提供測試串流

摘要:

  1. 媒體以不同的位元率編碼。
  2. 不同的位元率檔案可從 HTTP 伺服器取得。
  3. 用戶端網頁應用程式會選擇要透過 DASH 擷取及播放哪個位元率。

在影片區隔程序中,稱為媒體呈現說明 (MPD) 的 XML 資訊清單會以程式設計方式建構。這描述了適應集與表示法,包含時間長度和網址。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。然而,為了讓網頁開發人員享有更多彈性,瀏覽器廠商已改為要求 DASH 支援使用 MSE 的 JavaScript 程式庫,例如 dash.js。在 JavaScript 中導入 DASH,不需更新瀏覽器,即可自動調整演算法。使用 MSE 也能測試替代資訊清單格式和傳送機制,而不必變更瀏覽器。Google 的 Shaka Player 實作一個支援 EME 的 DASH 用戶端。

Mozilla Developer Network 提供操作說明,協助你瞭解如何使用 WebM 工具和 FFmpeg 區隔影片及建立 MPD。

結語

透過網路提供付費影片和音訊內容的費率相當高。無論是平板電腦、遊戲主機、連網電視或機上盒,每部新裝置都可透過 HTTP 串流播放主要內容供應商的媒體內容。超過 85% 的行動裝置和電腦版瀏覽器現在支援 <video><audio>,而 Cisco 估計在 2017 年時,影片將佔全球消費者網際網路流量的 80% 至 90%。由於大多數媒體外掛程式都依賴的 API 都是由瀏覽器廠商 首選支援,因此瀏覽器對受保護內容發布的支援變得越來越普遍。

延伸閱讀

規格和標準

文章