什麼是 EME?

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

EME 經過設計,可讓各種瀏覽器使用相同的應用程式和加密檔案,無論基礎保護系統為何。前者可透過標準化 API 和資料流進行,後者則透過常見加密的概念完成。

EME 是 HTMLMediaElement 規格的擴充功能,因此其名稱。「擴充功能」表示不一定要讓瀏覽器支援 EME:如果瀏覽器不支援加密媒體,就無法播放加密媒體,但不需遵循 HTML 規格要求 EME。在 EME 規格中:

本提案擴充了 HTMLMediaElement,提供 API 以控制受保護內容的播放。

這個 API 支援各種用途,無論是簡單的金鑰解密,還是高價值影片 (針對特定使用者代理程式的實作方式) 都沒問題。授權/金鑰交換機制由應用程式控管,可幫助開發完善的播放應用程式,並支援多種內容解密和保護技術。

此規格未定義內容保護或數位版權管理系統。而是定義了一個通用 API,可用於探索、選取這類系統並與其互動,以及較簡單的內容加密系統。您不必導入數位版權管理即可符合這個規範:只需導入 Clear Key 系統做為通用基準即可。

這個通用 API 支援一組簡易的內容加密功能,將應用程式功能 (例如驗證和授權) 提供給頁面作者。實際做法為要求網頁中介內容防護系統專屬的訊息,而不是假設加密系統和授權或其他伺服器之間的頻外通訊。

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

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

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

EME 如何運作?

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

如果有多種格式或轉碼器,可使用 MediaSource.isTypeSupported()HTMLMediaElement.canPlayType() 選擇正確的格式。 不過,CDM 僅支援瀏覽器支援的未加密內容子集。在選取格式和轉碼器之前,最好先交涉 MediaKeys 設定。如果應用程式等待加密事件,但 MediaKeys 顯示無法處理所選格式/轉碼器,可能就無法在不中斷播放的情況下切換。

建議的流程是使用 MediaKeysSystemAccess.getConfiguration() 交涉 MediaKeys,找出議定的設定。

如果只選擇一種格式/轉碼器,就不需要 getConfiguration()。不過,我們還是建議您先設定 MediaKeys。等待加密事件的唯一原因,是無法得知內容是否經過加密,但實際上不太可能如此。

  1. 網頁應用程式會嘗試播放含有一或多個加密串流的音訊或影片。
  2. 瀏覽器會辨識媒體已加密 (具體情形請見下方的方塊),並會以從加密相關媒體取得的中繼資料 (initData) 觸發加密事件。
  3. 應用程式處理加密的事件:

    1. 如果沒有任何 MediaKeys 物件與媒體元素建立關聯,請先使用 navigator.requestMediaKeySystemAccess() 選取可用的 Key System 來檢查可用的 Key Systems,然後再透過 MediaKeySystemAccess 物件為可用的 Key System 建立 MediaKeys 物件。請注意,MediaKeys 物件的初始化作業應在第一個加密事件之前發生。應用程式會獨立選取可用金鑰系統,負責取得授權伺服器網址。MediaKeys 物件代表所有可用於解密音訊或影片元素媒體的金鑰。這代表 CDM 執行個體,並且提供 CDM 執行個體的存取權,專門用於建立金鑰工作階段,可用於從授權伺服器取得金鑰。

    2. 建立 MediaKeys 物件後,請將其指派給媒體元素:setMediaKeys() 會將 MediaKeys 物件與 HTMLMediaElement 建立關聯,以便在播放期間使用其鍵 (亦即解碼時)。

  4. 應用程式透過呼叫 MediaKeys 的 createSession() 建立 MediaKeySession。這會建立 MediaKeySession,此項目代表授權的生命週期及其金鑰。

  5. 應用程式會透過在 MediaKeySession 上呼叫 generateRequest(),將加密處理常式取得的媒體資料傳送至 CDM,藉此產生授權要求。

  6. CDM 會觸發訊息事件:要求從授權伺服器取得金鑰。

  7. MediaKeySession 物件接收訊息事件,應用程式會將訊息傳送至授權伺服器 (例如透過 XHR)。

  8. 應用程式會接收來自授權伺服器的回應,並使用 MediaKeySession 的 update() 方法將資料傳送至 CDM。

  9. 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 授權伺服器取得金鑰。

這與只能處理完整垂直堆疊的舊版解決方案不同,包括通常也包含應用程式執行階段的單一用戶端。

通用加密 (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) 和其他解決方案正在開發中。

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,請參閱 MSE 入門

支援多種裝置、多平台、行動裝置 - 無論您稱呼它,網路通常是在可變更的連線環境中發生。動態的自動調整傳遞功能對於因應多裝置時代的頻寬限制和變化性而言至關重要。

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

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

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

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

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

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

媒體是以不同位元率進行數次編碼。每個編碼都稱為 Representation。並將這些區隔劃分成數個媒體區隔。用戶端會依序要求區隔,透過 HTTP 代表執行程式。表示法可分組為包含對等內容表示法的調整集。如果用戶端想要變更位元率,可以從目前的調整集挑選替代方案,並開始向該表示法要求區隔。為了讓用戶端更容易進行轉換,內容將採用這種編碼方式。除了多個媒體區隔以外,表示法通常也會具備「初始化區隔」。這可視為標頭,其中包含編碼、影格大小等相關資訊。用戶端必須先取得此表示法,才能使用該表示法的媒體區段。

摘要:

  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 的瀏覽器供應商 首選支援,因此瀏覽器對受保護內容發布的支援變得越來越顯著。

延伸閱讀

規格和標準

EME 規格:最新編輯器的草稿草稿 常見加密 (CENC) 媒體來源擴充功能:最新編輯器的草稿 DASH 標準 (是,這是 PDF) DASH 標準總覽

文章

DTG 網路研討會 (部分過時) 什麼是 EME? Henri Sivonen 媒體來源擴充功能初級 MPEG-DASH 測試串流:BBC R&D 網誌文章

試聽帶

清除 Key 示範:simpl.info/ck Media Source Extensions (MSE) 示範 Google 的 Shaka Player 實作支援 EME 的 DASH 用戶端

意見回饋: