如何播放受保護的媒體檔案

受保護的媒體檔案是具有使用內容相關規則的任何媒體檔案。 在某些情況下,受保護的媒體檔案會使用某種形式的數位版權管理來加密, (DRM) 加密。 若要播放受保護的媒體檔案,必須在 PMP () 的受保護媒體路徑內發生播放。 此外,使用者可能必須取得內容的許可權。

權利取得一詞是指應用程式必須在使用者播放內容之前執行的任何動作。 最常見的範例是取得 DRM 授權,但媒體基礎會定義可支援其他類型的權利取得的一般機制。 IMFContentEnabler介面會定義此泛型機制。

許可權取得必須在 PMP 外部完成,才能從應用程式程式進行。 媒體會話會透過由應用程式實作的 IMFContentProtectionManager 介面通知應用程式。 媒體會話會使用 IMFContentProtectionManager 介面,將內容啟用器物件轉送至應用程式。 內容啟用者會實作 IMFContentEnabler 介面。 應用程式會使用此介面來取得必要的許可權。

內容啟用者可能支援自動取得許可權,在此情況下,內容啟用者會實作整個程式,而應用程式只會監視狀態。 否則,應用程式必須使用非無訊息許可權取得,這是應用程式將 HTTP POST 資料傳送至內容啟用器所提供的 URL 的程式。

若要播放受保護的媒體,應用程式會遵循 如何使用 Media Foundation 播放媒體檔案主題中所提供的相同步驟,並執行下列額外步驟:

  1. 查詢媒體來源是否包含受保護的內容。 (選擇性。)
  2. 在 PMP 程式中建立媒體會話,而不是應用程式進程。
  3. 如果媒體會話收到通知,請執行許可權取得。 此作業是由應用程式以非同步方式執行。
  4. 完成非同步作業。

查詢受保護的內容

若要查詢媒體來源是否包含受保護的內容,請在媒體來源的簡報描述元上呼叫 MFRequireProtectedEnvironment 函式。 如果函式傳回S_OK,您必須使用 PMP 播放內容。 如果函式傳回S_FALSE,則不需要 PMP,而且您可以在應用程式程式中建立媒體會話。 或者,您也可以使用 PMP 播放兩種類型的內容、受保護和未受保護。 如果您這樣做,就不需要呼叫 MFRequireProtectedEnvironment

如需簡報描述項的詳細資訊,請參閱 簡報描述元

建立 PMP 媒體會話

若要在 PMP 中建立媒體會話,請呼叫 MFCreatePMPMediaSession。 此函式類似于 MFCreateMediaSession,但不會在應用程式的程式中建立媒體會話,而是在 PMP 程式中建立媒體會話。 應用程式會接收媒體會話 Proxy 物件的指標。 應用程式會在 Proxy 物件上呼叫 IMFMediaSession 方法,就像在媒體會話上一樣。 Proxy 物件會將呼叫轉送至跨進程界限的媒體會話。

建立 PMP 媒體會話,如下所示:

  1. 呼叫 MFCreateAttributes以建立新的屬性存放區。
  2. 在屬性存放區上 設定MF_SESSION_CONTENT_PROTECTION_MANAGER 屬性。 此屬性的值是應用程式 實作 IMFContentProtectionManager的指標。 呼叫 IMFAttributes::SetUnknown 來設定 屬性。
  3. 呼叫 MFCreatePMPMediaSession 以在 PMP 程式中建立媒體會話。 pConfiguration參數是屬性存放區之 IMFAttributes介面的指標。
IMFAttributes *pAttributes = NULL;
IMFMediaSession *pSession = NULL;

// Create the attribute store.
hr = MFCreateAttributes(&pAttributes, 1);

// Set the IMFContentProtectionManager pointer.
if (SUCCEEDED(hr))
{
    hr = pAttributes->SetUnknown(
        MF_SESSION_CONTENT_PROTECTION_MANAGER, 
        pCPM  // Your implementation of IMFContentProtectionManager.
        );
}

// Create the Media Session.
if (SUCCEEDED(hr))
{
    hr = MFCreatePMPMediaSession(
        0,
        pAttributes, 
        &pSession,
        NULL
    );
}

SAFE_RELEASE(pAttributes); // Release the attribute store.
// Use the Media Session to control playback (not shown).

接下來,建立播放拓撲並在媒體會話上排入佇列,如 建立播放拓撲中所述。

執行許可權取得

如果播放需要取得許可權,媒體會話會呼叫 IMFContentProtectionManager::BeginEnableContent。 此方法的 pEnablerActivate 參數是 IMFActivate 介面的指標。 使用此介面來建立內容啟用器物件,這會公開 IMFContentEnabler 介面。 然後使用內容啟用器來執行許可權取得步驟。

若要建立內容啟用器,請呼叫 IMFActivate::ActivateObject

IMFContentEnabler *pEnabler = NULL;
hr = pEnablerActivate->ActivateObject(
    IID_IMFContentEnabler, 
    (void**)&pEnabler
    );

針對IMFMediaEventGenerator介面查詢傳回的IMFContentEnabler指標。 使用此介面可從內容啟用器物件取得事件。 如需事件的詳細資訊,請參閱 媒體事件產生器

若要瞭解內容啟用器是否支援自動取得,請呼叫 IMFContentEnabler::IsAutomaticSupported。 如果這個方法傳 回 TRUE 值,應用程式應該使用自動擷取。 否則,請使用非無訊息擷取。

BeginEnableContent方法是非同步。 應用程式應該在應用程式的執行緒上執行取得步驟。 其中一種方法是將私人視窗訊息張貼至應用程式的主視窗,通知應用程式執行緒執行取得。 當作業擱置時,應用程式必須儲存回呼指標及其在BeginEnableContentpCallbackpunkState參數中所接收的狀態物件。 這些會用來完成非同步作業。

自動擷

若要執行自動取得,請呼叫 IMFContentEnabler::AutomaticEnable。 這個方法是非同步方法。 當作業完成時,內容啟用程式會傳送 MEEnablerCompleted 事件。 事件的狀態碼會指出作業是否成功。 如果 MEEnablerCompleted 事件的狀態碼NS_E_DRM_LICENSE_NOTACQUIRED,應用程式應該嘗試使用非無訊息取得。

當擷取作業進行中時,enabler 物件可能會傳送 MEEnablerProgress 事件來指出作業的進度。 若要取消作業,請呼叫 IMFContentEnabler::Cancel

非無訊息擷取

如果 IsAutomaticSupported 方法傳回 FALSEAutomaticEnable 方法失敗,錯誤碼NS_E_DRM_LICENSE_NOTACQUIRED,應用程式應該執行非無訊息下載,如下列步驟所述:

  1. 呼叫 IMFContentEnabler::GetEnableURL 以取得許可權取得的 URL。 這個方法也會傳回旗標,指出 URL 是否受信任。

  2. 呼叫 IMFContentEnabler::GetEnableData 以取得 HTTP POST 資料。

  3. 呼叫 IMFContentEnabler::MonitorEnable。 此方法會導致內容啟用器監視許可權取得動作的進度。

  4. 使用 HTTP POST 動作將資料提交至許可權取得 URL。 您可以使用 Internet Explorer 控制項或 Windows Internet (WinINet) API。

下列程式碼顯示步驟 1–3。 步驟 4 取決於應用程式的特定需求。

WCHAR   *sURL = NULL;  // URL.
DWORD   cchURL = 0;    // Size of the URL in characters.

// Trust status of the URL.
MF_URL_TRUST_STATUS  trustStatus = MF_LICENSE_URL_UNTRUSTED;

BYTE    *pPostData = NULL;  // Buffer to hold HTTP POST data.
DWORD   cbPostDataSize = 0; // Size of the buffer, in bytes.

HRESULT hr = S_OK;

// Get the URL. 
hr = m_pEnabler->GetEnableURL(&sURL, &cchURL, &trustStatus);

if (SUCCEEDED(hr))
{
    if (trustStatus != MF_LICENSE_URL_TRUSTED)
    {
        // The URL is not trusted. Do not proceed.
        hr = E_FAIL;
    }
}

// Monitor the rights acquisition. 
if (SUCCEEDED(hr))
{
    hr = m_pEnabler->MonitorEnable();
}

// Get the HTTP POST data.
if (SUCCEEDED(hr))
{
    hr = m_pEnabler->GetEnableData(&pPostData, &cbPostDataSize);
}

// Open the URL and send the HTTP POST data. (Not shown.)

// Release the buffers.
CoTaskMemFree(pPostData);
CoTaskMemFree(sURL);

當作業完成時,內容啟用程式會傳送 MEEnablerCompleted 事件。

完成非同步作業

當權限取得完成時,應用程式必須藉由叫用 BeginEnableContent 方法中提供的回呼指標來通知媒體會話。

  1. 呼叫 MFCreateAsyncResult來建立異步結果物件。
  2. 呼叫 MFInvokeCallback來叫用媒體會話的回呼。
  3. 媒體會話會呼叫 IMFContentProtectionManager::EndEnableContent。 在此方法的實作中,釋放您在 BeginEnableContent內配置的任何指標或資源。 傳回 HRESULT ,指出作業的整體成功。 如果許可權擷取失敗或使用者在完成之前取消,請傳回錯誤碼。

下列程式碼示範如何建立異步結果並叫用回呼。

IMFAsyncResult  *pResult = NULL;

// Create the asynchronous result object.
hr = MFCreateAsyncResult(NULL, pCallback, punkState, &pResult);

// Invoke the callback.
if (SUCCEEDED(hr))
{
    pResult->SetStatus(hrStatus);
    hr = MFInvokeCallback(pResult);
}
SAFE_RELEASE(pResult);

媒體會話

音訊/視訊播放