Воспроизведение защищенных файлов мультимедиа

Защищенный файл мультимедиа — это любой файл мультимедиа с связанными правилами использования содержимого. В некоторых случаях защищенный файл мультимедиа шифруется с помощью той или иной формы шифрования управления цифровыми правами (DRM). Чтобы воспроизвести защищенный файл мультимедиа, воспроизведение должно происходить внутри защищенного пути к мультимедиа (PMP). Кроме того, пользователю может потребоваться получить права на содержимое.

Термин приобретение прав относится к любому действию, которое приложение должно выполнить, прежде чем пользователь сможет воспроизвести содержимое. Наиболее распространенным примером является получение лицензии DRM, но Media Foundation определяет универсальный механизм, который может поддерживать другие типы приобретения прав. Интерфейс 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 для прокси-объекта так же, как и в сеансе мультимедиа. Прокси-объект перенаправит вызовы в сеанс мультимедиа через границу процесса.

Создайте сеанс мультимедиа 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 . Используйте этот интерфейс для создания объекта content enabler, который предоставляет интерфейс IMFContentEnabler . Затем используйте средство включения содержимого для выполнения шага получения прав.

Чтобы создать средство включения содержимого, вызовите IMFActivate::ActivateObject:

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

Запросите возвращенный указатель IMFContentEnabler для интерфейса IMFMediaEventGenerator . Используйте этот интерфейс для получения событий из объекта средства включения содержимого. Дополнительные сведения о событиях см. в разделе Генераторы событий мультимедиа.

Чтобы узнать, поддерживает ли средство включения содержимого автоматическое получение, позвоните в IMFContentEnabler::IsAutomaticSupported. Если этот метод возвращает значение TRUE, приложение должно использовать автоматическое получение. В противном случае используйте не автоматическое приобретение.

Метод BeginEnableContent является асинхронным. Приложение должно выполнить шаг получения в потоке приложения. Один из подходов заключается в публикации сообщения частного окна в окне main приложения, уведомляя поток приложения о выполнении приобретения. Пока операция находится в состоянии ожидания, приложение должно хранить указатель обратного вызова и полученный объект состояния в параметрах pCallback и punkStatebeginEnableContent. Они будут использоваться для завершения асинхронной операции.

Автоматическое приобретение

Чтобы выполнить автоматическое приобретение, вызовите 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. Отправьте данные по URL-адресу для получения прав с помощью действия HTTP POST. Вы можете использовать элемент управления Internet Обозреватель или API-интерфейсы Windows Internet (WinINet).

В следующем коде показаны шаги 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);

Сеанс мультимедиа

Воспроизведение звука/видео