共用方式為


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

受保護的媒體檔案是具有使用內容相關規則的任何媒體檔案。 在某些情況下,受保護的媒體檔案會使用某種形式的數字版權管理 (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 程式中建立媒體會話。 應用程式會接收到媒體會話的代理物件指標。 應用程式會呼叫 IMFMediaSession Proxy 物件上的方法,就像在媒體會話上一樣。 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 true值,則應用程式應該使用自動擷取。 否則,請使用非靜默擷取。

BeginEnableContent 方法是異步的。 應用程式應該在應用程式的線程上執行擷取步驟。 其中一種方法是將私人視窗訊息張貼至應用程式主視窗,通知應用程式線程執行擷取。 作業等待中時,應用程式必須將其在 BeginEnableContent的參數 pCallbackpunkState 中接收到的回呼指標和狀態物件進行儲存。 這些將用來完成異步操作。

自動獲取

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

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

非無訊息擷取

如果 IsAutomaticSupported 方法傳回 FALSE,或 AutomaticEnable 方法因錯誤碼 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 因特網 (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);

媒體會話

音訊/視訊播放