Lendo DRM-Protected arquivos ASF no DirectShow

[O recurso associado a esta página, DirectShow, é um recurso herdado. Ele foi substituído por MediaPlayer, IMFMediaEngine e Captura de Áudio/Vídeo na Media Foundation. Esses recursos foram otimizados para Windows 10 e Windows 11. A Microsoft recomenda fortemente que o novo código use MediaPlayer, IMFMediaEngine e Captura de Áudio/Vídeo no Media Foundation em vez de DirectShow, quando possível. A Microsoft sugere que o código existente que usa as APIs herdadas seja reescrito para usar as novas APIs, se possível.]

Este tópico descreve como usar o DirectShow para reproduzir arquivos de mídia protegidos com o DRM (Gerenciamento de Direitos Digitais) do Windows Media.

Conceitos de DRM

Proteger um arquivo de mídia com o DRM do Windows Media envolve duas etapas distintas:

  • O provedor de conteúdo empacota o arquivo, ou seja, criptografa o arquivo e anexa informações de licenciamento ao cabeçalho do arquivo ASF. As informações de licenciamento incluem uma URL em que o cliente pode obter a licença.
  • O aplicativo cliente adquire uma licença para o conteúdo.

O empacotamento ocorre antes que o arquivo seja distribuído. A aquisição de licença ocorre quando o usuário tenta reproduzir ou copiar o arquivo. A aquisição de licença pode ser silenciosa ou não silenciosa. A aquisição silenciosa não requer nenhuma interação com o usuário. A aquisição não silenciosa requer que o aplicativo abra uma janela do navegador e exiba uma página da Web para o usuário. Nesse ponto, talvez o usuário precise fornecer algum tipo de informação ao provedor de conteúdo. No entanto, ambos os tipos de aquisição de licença exigem que o cliente envie uma solicitação HTTP a um servidor de licença.

Versões do DRM

Existem várias versões do DRM do Windows Media. Da perspectiva de um aplicativo cliente, eles podem ser agrupados em duas categorias: DRM versão 1 e DRM versão 7 ou posterior. (A segunda categoria inclui as versões 9 e 10 do DRM, bem como a versão 7.) O motivo para categorizar as versões do DRM dessa forma é que as licenças da versão 1 são tratadas de forma um pouco diferente das licenças da versão 7 ou posterior. Nesta documentação, o termo licença versão 7 significa a versão 7 ou posterior.

Também é importante distinguir o empacotamento DRM da licença DRM. Se o arquivo estiver empacotado usando o Windows Media Rights Manager versão 7 ou posterior, o cabeçalho DRM poderá conter uma URL de licença versão 1, além da URL de licença da versão 7. A URL de licença da versão 1 permite que jogadores mais antigos que não dão suporte à versão 7 obtenham uma licença para o conteúdo. No entanto, o inverso não é verdadeiro, portanto, um arquivo com o empacotamento da versão 1 não pode ter uma URL de licença versão 7.

Nível de segurança do aplicativo

Para reproduzir arquivos protegidos por DRM, o aplicativo cliente deve ser vinculado a uma biblioteca estática fornecida em formato binário pela Microsoft. Essa biblioteca, que identifica exclusivamente o aplicativo, às vezes é chamada de biblioteca stub. A biblioteca stub tem um nível de segurança atribuído, cujo valor é determinado pelo contrato de licença assinado quando você obteve a biblioteca stub.

O provedor de conteúdo define um nível de segurança mínimo necessário para adquirir a licença. Se o nível de segurança da biblioteca de stub for menor que o nível mínimo de segurança exigido pelo servidor de licença, o aplicativo não poderá obter a licença.

Individualização

Para aumentar a segurança, um aplicativo pode atualizar os componentes drm no computador do cliente. Essa atualização, chamada individualização, diferencia a cópia do aplicativo do usuário de todas as outras cópias do mesmo aplicativo. O cabeçalho DRM de um arquivo protegido pode especificar um nível mínimo de individualização. (Para obter mais informações, consulte a documentação de WMRMHeader.IndividualizedVersion no SDK do Windows Media Rights Manager.)

O Serviço de Individualização da Microsoft manipula informações do usuário. Portanto, antes de seu aplicativo ser individualizado, você deve exibir a Política de Privacidade da Microsoft ou fornecer um link para ele (consulte Política de Privacidade da Microsoft).

Fornecer o certificado de software

Para habilitar o aplicativo a usar a licença DRM, o aplicativo deve fornecer um certificado de software ou uma chave para o Gerenciador de Grafo de Filtro. Essa chave está contida em uma biblioteca estática individualizada para o aplicativo. Para obter informações sobre como obter a biblioteca individualizada, consulte Obtendo a biblioteca drm necessária na documentação do SDK do Formato de Mídia do Windows.

Para fornecer a chave de software, execute as seguintes etapas:

  1. Link para a biblioteca estática.
  2. Implemente a interface IServiceProvider .
  3. Consulte o Gerenciador de Grafo de Filtro para a interface IObjectWithSite .
  4. Chame IObjectWithSite::SetSite com um ponteiro para a implementação de IServiceProvider.
  5. O Gerenciador de Grafo de Filtro chamará IServiceProvider::QueryService, especificando IID_IWMReader para o identificador de serviço.
  6. Na implementação do QueryService, chame WMCreateCertificate para criar a chave de software.

O código a seguir mostra como implementar o método QueryService :

STDMETHODIMP Player::QueryService(REFIID siid, REFIID riid, void **ppv)
{
    if (ppv == NULL ) 
    { 
        return E_POINTER; 
    }

    if (siid == __uuidof(IWMReader) && riid == __uuidof(IUnknown))
    {
        IUnknown *punkCert;

        HRESULT hr = WMCreateCertificate(&punkCert);

        if (SUCCEEDED(hr))
        {
            *ppv = (void *) punkCert;
        }

        return hr;
    }
    return E_NOINTERFACE;
}

O código a seguir mostra como chamar SetSite no Gerenciador de Grafo de Filtro:

HRESULT Player::CreateFilterGraph()
{
    CComPtr<IObjectWithSite> pSite;

    HRESULT hr = pGraph.CoCreateInstance(CLSID_FilterGraph);

    if (FAILED(hr))
    {
        goto done;
    }

    // Register the application as a site (service).
    hr = pGraph->QueryInterface(&pSite);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = pSite->SetSite(this);


done:
    return hr;
}

Criando o gráfico de reprodução

Para reproduzir um arquivo ASF protegido por DRM, execute as seguintes etapas:

  1. Crie o Gerenciador de Grafo de Filtro e use a interface IMediaEventEx para registrar-se em eventos de grafo.
  2. Chame CoCreateInstance para criar uma nova instância do filtro leitor do ASF do WM .
  3. Chame IFilterGraph::AddFilter para adicionar o filtro ao grafo de filtro.
  4. Consulte o filtro para a interface IFileSourceFilter .
  5. Chame IFileSourceFilter::Load com a URL do arquivo.
  6. Manipular eventos de EC_WMT_EVENT .
  7. No primeiro evento EC_WMT_EVENT , consulte o filtro leitor asf do WM para a interface IServiceProvider .
  8. Chame IServiceProvider::QueryService para obter um ponteiro para a interface IWMDRMReader .
  9. Chame IGraphBuilder::Render para renderizar os pinos de saída do filtro leitor do ASF do WM .

Observação

Ao abrir um arquivo protegido por DRM, não chame IGraphBuilder::RenderFile para criar o grafo de filtro. O filtro leitor do ASF do WM não pode se conectar a nenhum outro filtro até que a licença DRM seja adquirida. Esta etapa exige que o aplicativo use a interface IWMDRMReader , que deve ser obtida do filtro, conforme descrito nas etapas 7 a 8. Portanto, você deve criar o filtro e adicioná-lo ao grafo

 

Observação

É importante registrar-se para eventos de grafo (etapa 1) antes de adicionar o filtro leitor do ASF do WM ao grafo (etapa 3), pois o aplicativo deve lidar com os eventos EC_WMT_EVENT . Os eventos são enviados quando Load é chamado (etapa 5).

 

O código a seguir mostra como criar o grafo:

HRESULT Player::LoadMediaFile(PCWSTR pwszFile)
{


    BOOL bIsWindowsMediaFile = IsWindowsMediaFile(pwszFile);

    HRESULT hr = S_OK;

    // If this is the first time opening the file, create the
    // filter graph and add the WM ASF Reader filter.

    if (m_DRM.State() == DRM_INITIAL)
    {
        hr = CreateFilterGraph();
        if (FAILED(hr))
        {
            goto done;
        }

        // Use special handling for Windows Media files.
        if (bIsWindowsMediaFile)
        {
            // Add the ASF Reader filter to the graph.
            hr = m_pReader.CoCreateInstance(CLSID_WMAsfReader);
            if (FAILED(hr))
            {
                goto done;
            }

            hr = pGraph->AddFilter(m_pReader, NULL);
            if (FAILED(hr))
            {
                goto done;
            }

            hr = m_pReader->QueryInterface(&m_pFileSource);
            if (FAILED(hr))
            {
                goto done;
            }
        }
    }

    if (bIsWindowsMediaFile)
    {
            hr = m_pFileSource->Load(pwszFile, NULL);
C++
            if (FAILED(hr))            {                goto done;            }            hr = RenderOutputPins(pGraph, m_pReader);    }    else    {        // Not a Windows Media file, so just render the standard way.        hr = pGraph->RenderFile(pwszFile, NULL);    }done:    return hr;}

No código anterior, a RenderOutputPins função enumera os pinos de saída no filtro Leitor do ASF do WM e chama IGraphBuilder::Render para cada pin.

HRESULT RenderOutputPins(IGraphBuilder *pGraph, IBaseFilter *pFilter)
{
    CComPtr<IEnumPins>  pEnumPin = NULL;
    CComPtr<IPin>       pConnectedPin;
    CComPtr<IPin>       pPin;

    // Enumerate all pins on the filter
    HRESULT hr = pFilter->EnumPins(&pEnumPin);
    if (FAILED(hr))
    {
        goto done;
    }

    // Step through every pin, looking for the output pins.
    while (S_OK == (hr = pEnumPin->Next(1, &pPin, NULL)))
    {
        // Skip connected pins.
        hr = pPin->ConnectedTo(&pConnectedPin);
        if (hr == VFW_E_NOT_CONNECTED)
        {
            PIN_DIRECTION PinDirection;
            hr = pPin->QueryDirection(&PinDirection);

            if ((S_OK == hr) && (PinDirection == PINDIR_OUTPUT))
            {
                hr = pGraph->Render(pPin);
            }
        }

        pConnectedPin.Release();
        pPin.Release();

        // If there was an error, stop enumerating.
        if (FAILED(hr))
        {
            break;
        }
    }

done:
    return hr;
}

O código a seguir mostra como obter um ponteiro para a interface IWMDRMReader do Leitor de ASF do WM:

HRESULT DrmManager::Initialize(IBaseFilter *pFilter)
{


    CComPtr<IServiceProvider> pService;
    CComPtr<IWMDRMReader> pDrmReader;

    HRESULT hr = pFilter->QueryInterface(&pService);
    if (SUCCEEDED(hr))
    {
        hr = pService->QueryService(
            __uuidof(IWMDRMReader), IID_PPV_ARGS(&m_pDrmReader));
    }
    return hr;
}

Lendo arquivos ASF no DirectShow