Lettura di DRM-Protected file ASF in DirectShow

[La funzionalità associata a questa pagina, DirectShow, è una funzionalità legacy. È stata sostituita da MediaPlayer, IMFMediaEngine e Audio/Video Capture in Media Foundation. Queste funzionalità sono state ottimizzate per Windows 10 e Windows 11. Microsoft consiglia vivamente che il nuovo codice usi MediaPlayer, IMFMediaEngine e Audio/Video Capture in Media Foundation invece di DirectShow, quando possibile. Microsoft suggerisce che il codice esistente che usa le API legacy venga riscritto per usare le nuove API, se possibile.

Questo argomento descrive come usare DirectShow per riprodurre file multimediali protetti con Windows Media Digital Rights Management (DRM).

Concetti relativi a DRM

La protezione di un file multimediale con DRM Di Windows Media prevede due passaggi distinti:

  • Il provider di contenuti crea un pacchetto del file, ovvero crittografa il file e allega le informazioni sulle licenze all'intestazione del file ASF. Le informazioni sulla licenza includono un URL in cui il client può ottenere la licenza.
  • L'applicazione client acquisisce una licenza per il contenuto.

La creazione di pacchetti avviene prima della distribuzione del file. L'acquisizione della licenza si verifica quando l'utente tenta di riprodurre o copiare il file. L'acquisizione delle licenze può essere invisibile all'utente o non invisibile all'utente. L'acquisizione invisibile all'utente non richiede alcuna interazione. L'acquisizione non invisibile all'utente richiede all'applicazione di aprire una finestra del browser e visualizzare una pagina Web. A questo punto, l'utente potrebbe dover fornire alcune informazioni al provider di contenuti. Tuttavia, entrambi i tipi di acquisizione delle licenze richiedono al client di inviare una richiesta HTTP a un server licenze.

Versioni DRM

Esistono diverse versioni di DRM di Windows Media. Dal punto di vista di un'applicazione client, possono essere raggruppati in due categorie: DRM versione 1 e DRM versione 7 o successiva. La seconda categoria include le versioni DRM 9 e 10, nonché la versione 7. Il motivo della categorizzazione delle versioni DRM in questo modo è che le licenze della versione 1 vengono gestite in modo leggermente diverso rispetto alle licenze 7 o successive. In questa documentazione il termine versione 7 indica la versione 7 o successiva.

È anche importante distinguere la creazione di pacchetti DRM dalla licenza DRM. Se il file viene incluso in un pacchetto con Windows Media Rights Manager versione 7 o successiva, l'intestazione DRM può contenere un URL di licenza versione 1 oltre all'URL della licenza della versione 7. L'URL della licenza versione 1 consente ai lettori meno recenti che non supportano la versione 7 di ottenere una licenza per il contenuto. Tuttavia, il contrario non è vero, quindi un file con pacchetto versione 1 non può avere un URL di licenza versione 7.

Livello di sicurezza delle applicazioni

Per riprodurre file protetti da DRM, l'applicazione client deve essere collegata a una libreria statica fornita in formato binario da Microsoft. Questa libreria, che identifica in modo univoco l'applicazione, viene talvolta denominata libreria stub. La libreria stub ha un livello di sicurezza assegnato, il cui valore è determinato dal contratto di licenza firmato quando è stata ottenuta la libreria stub.

Il provider di contenuti imposta un livello di sicurezza minimo necessario per acquisire la licenza. Se il livello di sicurezza della libreria stub è inferiore al livello di sicurezza minimo richiesto dal server licenze, l'applicazione non può ottenere la licenza.

Individualizzazione

Per aumentare la sicurezza, un'applicazione può aggiornare i componenti DRM nel computer del client. Questo aggiornamento, denominato individualizzazione, distingue la copia dell'utente dell'applicazione da tutte le altre copie della stessa applicazione. L'intestazione DRM di un file protetto può specificare un livello di individualizzazione minimo. Per altre informazioni, vedere la documentazione per WMRMHeader.IndividualizedVersion in Windows Media Rights Manager SDK.

Il servizio di individualizzazione Microsoft gestisce le informazioni dell'utente. Pertanto, prima che l'applicazione venga personalizzata, è necessario visualizzare l'Informativa sulla privacy di Microsoft o fornire un collegamento (vedere Informativa sulla privacy di Microsoft).

Specificare il certificato software

Per consentire all'applicazione di usare la licenza DRM, l'applicazione deve fornire un certificato software o una chiave per Filter Graph Manager. Questa chiave è contenuta in una libreria statica individualizzata per l'applicazione. Per informazioni su come ottenere la libreria personalizzata, vedere Ottenere la libreria DRM necessaria nella documentazione di Windows Media Format SDK.

Per fornire la chiave software, seguire questa procedura:

  1. Collegamento alla libreria statica.
  2. Implementare l'interfaccia IServiceProvider .
  3. Eseguire una query su Filter Graph Manager per l'interfaccia IObjectWithSite .
  4. Chiamare IObjectWithSite::SetSite con un puntatore all'implementazione di IServiceProvider.
  5. Filter Graph Manager chiamerà IServiceProvider::QueryService, specificando IID_IWMReader per l'identificatore del servizio.
  6. Nell'implementazione di QueryService chiamare WMCreateCertificate per creare la chiave software.

Il codice seguente illustra come implementare il metodo 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;
}

Il codice seguente illustra come chiamare SetSite in Filter Graph Manager:

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

Creazione del grafico di riproduzione

Per riprodurre un file ASF protetto da DRM, seguire questa procedura:

  1. Creare Filter Graph Manager e usare l'interfaccia IMediaEventEx per eseguire la registrazione per gli eventi del grafo.
  2. Chiamare CoCreateInstance per creare una nuova istanza del filtro lettore ASF WM .
  3. Chiamare IFilterGraph::AddFilter per aggiungere il filtro al grafico del filtro.
  4. Eseguire una query sul filtro per l'interfaccia IFileSourceFilter .
  5. Chiamare IFileSourceFilter::Load con l'URL del file.
  6. Gestire eventi EC_WMT_EVENT .
  7. Nel primo evento EC_WMT_EVENT eseguire una query sul filtro lettore ASF WM per l'interfaccia IServiceProvider .
  8. Chiamare IServiceProvider::QueryService per ottenere un puntatore all'interfaccia IWMDRMReader .
  9. Chiamare IGraphBuilder::Render per eseguire il rendering dei pin di output del filtro lettore ASF WM .

Nota

Quando si apre un file protetto da DRM, non chiamare IGraphBuilder::RenderFile per creare il grafico del filtro. Il filtro lettore ASF WM non può connettersi ad altri filtri fino a quando non viene acquisita la licenza DRM. Questo passaggio richiede all'applicazione di usare l'interfaccia IWMDRMReader , che deve essere ottenuta dal filtro, come descritto nei passaggi da 7 a 8. Pertanto, è necessario creare il filtro e aggiungerlo al grafico

 

Nota

È importante eseguire la registrazione per gli eventi del grafo (passaggio 1) prima di aggiungere il filtro lettore ASF WM al grafico (passaggio 3), perché l'applicazione deve gestire gli eventi EC_WMT_EVENT . Gli eventi vengono inviati quando viene chiamato Load (passaggio 5).

 

Il codice seguente illustra come compilare il grafico:

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

Nel codice precedente la RenderOutputPins funzione enumera i pin di output nel filtro lettore ASF WM e chiama IGraphBuilder::Render per ogni 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;
}

Il codice seguente illustra come ottenere un puntatore all'interfaccia IWMDRMReader dal lettore WM ASF:

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

Lettura di file ASF in DirectShow