Cómo reproducir archivos multimedia protegidos

Un archivo multimedia protegido es cualquier archivo multimedia que tenga reglas asociadas para usar el contenido. En algunos casos, un archivo multimedia protegido se cifra mediante algún tipo de cifrado de administración de derechos digitales (DRM). Para reproducir un archivo multimedia protegido, la reproducción debe producirse dentro de la ruta de acceso multimedia protegida (PMP). Además, es posible que el usuario tenga que adquirir derechos para el contenido.

El término adquisición de derechos hace referencia a cualquier acción que la aplicación debe realizar antes de que el usuario pueda reproducir el contenido. El ejemplo más común es obtener una licencia DRM, pero Media Foundation define un mecanismo genérico que puede admitir otros tipos de adquisición de derechos. La interfaz IMFContentEnabler define este mecanismo genérico.

La adquisición de derechos debe realizarse fuera del PMP, desde el proceso de aplicación. La sesión multimedia notifica a la aplicación a través de la interfaz IMFContentProtectionManager , que la aplicación implementa. La sesión multimedia usa la interfaz IMFContentProtectionManager para reenviar un objeto de habilitador de contenido a la aplicación. Los habilitadores de contenido implementan la interfaz IMFContentEnabler . La aplicación usa esta interfaz para adquirir los derechos necesarios.

Un habilitador de contenido puede admitir la adquisición automática de derechos, en cuyo caso el habilitador de contenido implementa todo el proceso y la aplicación simplemente supervisa el estado. De lo contrario, la aplicación debe usar la adquisición de derechos no silenciosas, que es un proceso en el que la aplicación envía datos HTTP POST a una dirección URL proporcionada por el habilitador de contenido.

Para reproducir medios protegidos, una aplicación sigue los mismos pasos que se indican en el tema Cómo reproducir archivos multimedia con Media Foundation, con los pasos adicionales siguientes:

  1. Consulte si el origen multimedia contiene contenido protegido. (Opcional).
  2. Cree la sesión multimedia en el proceso PMP, en lugar del proceso de aplicación.
  3. Realice la adquisición de derechos, si se le notifica que lo haga la sesión multimedia. La aplicación realiza esta operación de forma asincrónica.
  4. Complete la operación asincrónica.

Consulta de contenido protegido

Para consultar si un origen multimedia contiene contenido protegido, llame a la función MFRequireProtectedEnvironment en el descriptor de presentación del origen multimedia. Si la función devuelve S_OK, debe usar el PMP para reproducir el contenido. Si la función devuelve S_FALSE, el PMP no es necesario y puede crear la sesión multimedia en el proceso de aplicación. Como alternativa, puede usar el PMP para reproducir ambos tipos de contenido, protegidos y no protegidos. Si lo hace, no es necesario llamar a MFRequireProtectedEnvironment.

Para obtener más información sobre los descriptores de presentación, vea Descriptores de presentación.

Creación de la sesión de medios PMP

Para crear la sesión multimedia en el PMP, llame a MFCreatePMPMediaSession. Esta función es similar a MFCreateMediaSession, pero en lugar de crear la sesión multimedia en el proceso de la aplicación, crea la sesión multimedia en el proceso de PMP. La aplicación recibe un puntero a un objeto proxy para la sesión multimedia. La aplicación llama a los métodos IMFMediaSession en el objeto proxy, como lo haría en la sesión multimedia. El objeto proxy reenvía las llamadas a la sesión multimedia a través del límite del proceso.

Cree la sesión de medios PMP de la siguiente manera:

  1. Cree un almacén de atributos mediante una llamada a MFCreateAttributes.
  2. Establezca el atributo MF_SESSION_CONTENT_PROTECTION_MANAGER en el almacén de atributos. El valor de este atributo es un puntero a la implementación de la aplicación de IMFContentProtectionManager. Llame a IMFAttributes::SetUnknown para establecer el atributo.
  3. Llame a MFCreatePMPMediaSession para crear la sesión multimedia en el proceso PMP. El parámetro pConfiguration es un puntero a la interfaz IMFAttributes del almacén de atributos.
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).

A continuación, cree una topología de reproducción y ponerla en cola en la sesión multimedia, como se describe en Crear topologías de reproducción.

Realizar adquisición de derechos

Si la reproducción requiere la adquisición de derechos, la sesión multimedia llama a IMFContentProtectionManager::BeginEnableContent. El parámetro pEnablerActivate de este método es un puntero a la interfaz IMFActivate . Utilice esta interfaz para crear el objeto de habilitador de contenido, que expone la interfaz IMFContentEnabler . A continuación, use el habilitador de contenido para realizar el paso de adquisición de derechos.

Para crear el habilitador de contenido, llame a IMFActivate::ActivateObject:

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

Consulte el puntero IMFContentEnabler devuelto para la interfaz IMFMediaEventGenerator . Use esta interfaz para obtener eventos del objeto de habilitador de contenido. Para obtener más información sobre los eventos, vea Generadores de eventos multimedia.

Para averiguar si el habilitador de contenido admite la adquisición automática, llame a IMFContentEnabler::IsAutomaticSupported. Si este método devuelve el valor TRUE, la aplicación debe usar la adquisición automática. De lo contrario, use la adquisición no silenciosa.

El método BeginEnableContent es asincrónico. La aplicación debe realizar el paso de adquisición en el subproceso de la aplicación. Un enfoque consiste en publicar un mensaje de ventana privada en la ventana principal de la aplicación, notificando al subproceso de aplicación que realice la adquisición. Mientras la operación está pendiente, la aplicación debe almacenar el puntero de devolución de llamada y el objeto de estado que recibió en los parámetros pCallback y punkState de BeginEnableContent. Se usarán para completar la operación asincrónica.

Adquisición automática

Para realizar la adquisición automática, llame a IMFContentEnabler::AutomaticEnable. Este método es asincrónico. Una vez completada la operación, el habilitador de contenido envía un evento MEEnablerCompleted . El código de estado del evento indica si la operación se realizó correctamente. Si el código de estado del evento MEEnablerCompleted es NS_E_DRM_LICENSE_NOTACQUIRED, la aplicación debe intentar usar la adquisición no silenciosa.

Mientras la operación de adquisición está en curso, el objeto enabler podría enviar el evento MEEnablerProgress para indicar el progreso de la operación. Para cancelar la operación, llame a IMFContentEnabler::Cancel.

Adquisición no silenciosa

Si el método IsAutomaticSupported devuelve FALSE o el método AutomaticEnable produce un error con el código de error NS_E_DRM_LICENSE_NOTACQUIRED, la aplicación debe realizar una adquisición no silenciosa, como se describe en los pasos siguientes:

  1. Llame a IMFContentEnabler::GetEnableURL para obtener la dirección URL de la adquisición de derechos. Este método también devuelve una marca que indica si la dirección URL es de confianza.

  2. Llame a IMFContentEnabler::GetEnableData para obtener los datos HTTP POST.

  3. Llame a IMFContentEnabler::MonitorEnable. Este método hace que el habilitador de contenido supervise el progreso de la acción de adquisición de derechos.

  4. Envíe los datos a la dirección URL de adquisición de derechos mediante una acción HTTP POST. Puede usar el control Internet Explorer o las API de Windows Internet (WinINet).

En el código siguiente se muestran los pasos 1 a 3. El paso 4 depende de los requisitos concretos de la aplicación.

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);

Una vez completada la operación, el habilitador de contenido envía un evento MEEnablerCompleted .

Completar la operación asincrónica

Cuando la adquisición de derechos se complete correctamente o de otro modo, la aplicación debe notificar a la sesión multimedia invocando el puntero de devolución de llamada especificado en el método BeginEnableContent .

  1. Cree un objeto de resultado asincrónico llamando a MFCreateAsyncResult.
  2. Invoque la devolución de llamada de la sesión multimedia llamando a MFInvokeCallback.
  3. La sesión multimedia llamará a IMFContentProtectionManager::EndEnableContent. En la implementación de este método, libere los punteros o recursos asignados dentro de BeginEnableContent. Devuelve un HRESULT que indica el éxito general de la operación. Si se produjo un error en la adquisición de derechos o el usuario canceló antes de que se completara, devuelva un código de error.

En el código siguiente se muestra cómo crear el resultado asincrónico e invocar la devolución de llamada.

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);

Sesión multimedia

Reproducción de audio y vídeo