보호된 미디어 파일을 재생하는 방법

보호된 미디어 파일은 콘텐츠 사용에 대한 관련 규칙이 있는 모든 미디어 파일입니다. 경우에 따라 보호된 미디어 파일은 일종의 DRM(디지털 권한 관리) 암호화를 사용하여 암호화됩니다. 보호된 미디어 파일을 재생하려면 PMP(보호된 미디어 경로) 내에서 재생이 발생해야 합니다. 또한 사용자는 콘텐츠에 대한 권한을 획득해야 할 수도 있습니다.

권한 획득이라는 용어는 사용자가 콘텐츠를 재생하기 전에 애플리케이션이 수행해야 하는 모든 작업을 나타냅니다. 가장 일반적인 예는 DRM 라이선스를 얻는 것이지만 Media Foundation은 다른 유형의 권한 획득을 지원할 수 있는 제네릭 메커니즘을 정의합니다. IMFContentEnabler 인터페이스는 이 제네릭 메커니즘을 정의합니다.

권한 획득은 애플리케이션 프로세스에서 PMP 외부에서 수행해야 합니다. 미디어 세션은 애플리케이션에 의해 구현되는 IMFContentProtectionManager 인터페이스를 통해 애플리케이션에 알릴 수 있습니다. 미디어 세션은 IMFContentProtectionManager 인터페이스를 사용하여 콘텐츠 사용자 개체를 애플리케이션에 전달합니다. 콘텐츠 지원자는 IMFContentEnabler 인터페이스를 구현합니다. 애플리케이션은 이 인터페이스를 사용하여 필요한 권한을 획득합니다.

콘텐츠 사용 프로그램은 자동 권한 획득을 지원할 수 있습니다. 이 경우 콘텐츠 사용 프로그램이 전체 프로세스를 구현하고 애플리케이션은 단순히 상태 모니터링합니다. 그렇지 않으면 애플리케이션은 비사일적 권한 획득을 사용해야 합니다. 이 권한 획득은 애플리케이션이 콘텐츠 사용 프로그램에서 제공하는 URL로 HTTP POST 데이터를 보내는 프로세스입니다.

보호된 미디어를 재생하기 위해 애플리케이션은 다음 추가 단계를 통해 Media Foundation을 사용하여 미디어 파일을 재생하는 방법 항목에 제공된 동일한 단계를 따릅니다.

  1. 미디어 원본에 보호된 콘텐츠가 포함되어 있는지 여부를 쿼리합니다. 선택 사항입니다.
  2. 애플리케이션 프로세스 대신 PMP 프로세스에서 미디어 세션을 만듭니다.
  3. 미디어 세션에서 이를 알리면 권한 획득을 수행합니다. 이 작업은 애플리케이션에서 비동기적으로 수행됩니다.
  4. 비동기 작업을 완료합니다.

보호된 콘텐츠 쿼리

미디어 원본에 보호된 콘텐츠가 포함되어 있는지 여부를 쿼리하려면 미디어 원본의 프레젠테이션 설명자에서 MFRequireProtectedEnvironment 함수를 호출합니다. 함수가 S_OK 반환하는 경우 PMP를 사용하여 콘텐츠를 재생해야 합니다. 함수가 S_FALSE 반환하는 경우 PMP가 필요하지 않으며 애플리케이션 프로세스에서 미디어 세션을 만들 수 있습니다. 또는 PMP를 사용하여 보호된 콘텐츠와 보호되지 않은 두 가지 유형의 콘텐츠를 모두 재생할 수 있습니다. 이렇게 하면 MFRequireProtectedEnvironment를 호출할 필요가 없습니다.

프레젠테이션 설명자에 대한 자세한 내용은 프레젠테이션 설명자를 참조하세요.

PMP 미디어 세션 만들기

PMP에서 미디어 세션을 만들려면 MFCreatePMPMediaSession을 호출합니다. 이 함수는 MFCreateMediaSession과 유사하지만 애플리케이션 프로세스에서 미디어 세션을 만드는 대신 PMP 프로세스에서 미디어 세션을 만듭니다. 애플리케이션은 미디어 세션의 프록시 개체에 대한 포인터를 받습니다. 애플리케이션은 미디어 세션에서와 마찬가지로 프록시 개체에서 IMFMediaSession 메서드를 호출합니다. 프록시 개체는 프로세스 경계를 넘어 미디어 세션에 호출을 전달합니다.

다음과 같이 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 메서드가 FALSE를 반환하거나 오류 코드 NS_E_DRM_LICENSE_NOTACQUIRED AutomaticEnable 메서드가 실패하는 경우 애플리케이션은 다음 단계에 설명된 대로 자동이 아닌 취득을 수행해야 합니다.

  1. IMFContentEnabler::GetEnableURL을 호출하여 권한 획득 URL을 가져옵니다. 또한 이 메서드는 URL을 신뢰할 수 있는지 여부를 나타내는 플래그를 반환합니다.

  2. IMFContentEnabler::GetEnableData를 호출하여 HTTP POST 데이터를 가져옵니다.

  3. IMFContentEnabler::MonitorEnable을 호출합니다. 이 방법을 사용하면 콘텐츠 사용자가 권한 획득 작업의 진행률을 모니터링합니다.

  4. HTTP POST 작업을 사용하여 권한 획득 URL에 데이터를 제출합니다. 인터넷 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);

미디어 세션

오디오/비디오 재생