Share via


DirectShow에서 DRM-Protected ASF 파일 읽기

[이 페이지와 연결된 기능인 DirectShow는 레거시 기능입니다. MediaPlayer, IMFMediaEngine 및 Media Foundation의 오디오/비디오 캡처로 대체되었습니다. 이러한 기능은 Windows 10 및 Windows 11 최적화되었습니다. 가능한 경우 새 코드가 DirectShow 대신 Media Foundation에서 MediaPlayer, IMFMediaEngine오디오/비디오 캡처를 사용하는 것이 좋습니다. 가능한 경우 레거시 API를 사용하는 기존 코드를 다시 작성하여 새 API를 사용하도록 제안합니다.]

이 항목에서는 DirectShow를 사용하여 Windows Media DRM(디지털 권한 관리)으로 보호되는 미디어 파일을 재생하는 방법을 설명합니다.

DRM 개념

Windows Media DRM을 사용하여 미디어 파일을 보호하려면 다음 두 가지 단계를 수행해야 합니다.

  • 콘텐츠 공급자는 파일을 패키지합니다. 즉, 파일을 암호화하고 라이선스 정보를 ASF 파일 헤더에 연결합니다. 라이선스 정보에는 클라이언트가 라이선스를 얻을 수 있는 URL이 포함됩니다.
  • 클라이언트 애플리케이션은 콘텐츠에 대한 라이선스를 획득합니다.

패키징은 파일이 배포되기 전에 발생합니다. 라이선스 취득은 사용자가 파일을 재생하거나 복사하려고 할 때 발생합니다. 라이선스 취득은 자동 또는 사용일 수 있습니다. 자동 획득에는 사용자와의 상호 작용이 필요하지 않습니다. 자동이 아닌 취득을 사용하려면 애플리케이션이 브라우저 창을 열고 사용자에게 웹 페이지를 표시해야 합니다. 이 시점에서 사용자는 콘텐츠 공급자에게 일종의 정보를 제공해야 할 수 있습니다. 그러나 두 유형의 라이선스 획득 모두 클라이언트가 라이선스 서버에 HTTP 요청을 제출해야 합니다.

DRM 버전

여러 버전의 Windows Media DRM이 있습니다. 클라이언트 애플리케이션의 관점에서 DRM 버전 1 및 DRM 버전 7 이상의 두 가지 범주로 그룹화할 수 있습니다. (두 번째 범주에는 DRM 버전 9 및 10과 버전 7이 포함됩니다.) 이러한 방식으로 DRM 버전을 분류하는 이유는 버전 1 라이선스가 버전 7 이상 라이선스와 다소 다르게 처리되기 때문입니다. 이 설명서에서 버전 7 라이선스 라는 용어는 버전 7 이상을 의미합니다.

DRM 패키징을 DRM 라이선스와 구분하는 것도 중요합니다. 파일이 Windows Media Rights Manager 버전 7 이상을 사용하여 패키지된 경우 DRM 헤더에는 버전 7 라이선스 URL 외에 버전 1 라이선스 URL이 포함될 수 있습니다. 버전 1 라이선스 URL을 사용하면 버전 7을 지원하지 않는 이전 플레이어가 콘텐츠에 대한 라이선스를 얻을 수 있습니다. 그러나 반대는 true가 아니므로 버전 1 패키징이 있는 파일에는 버전 7 라이선스 URL이 있을 수 없습니다.

애플리케이션 보안 수준

DRM으로 보호된 파일을 재생하려면 클라이언트 애플리케이션을 Microsoft에서 이진 형식으로 제공하는 정적 라이브러리에 연결해야 합니다. 애플리케이션을 고유하게 식별하는 이 라이브러리를 스텁 라이브러리라고도 합니다. 스텁 라이브러리에는 할당된 보안 수준이 있으며, 그 값은 스텁 라이브러리를 가져올 때 서명한 사용권 계약에 따라 결정됩니다.

콘텐츠 공급자는 라이선스를 획득하는 데 필요한 최소 보안 수준을 설정합니다. 스텁 라이브러리의 보안 수준이 라이선스 서버에 필요한 최소 보안 수준보다 작으면 애플리케이션에서 라이선스를 얻을 수 없습니다.

개별화

보안을 강화하기 위해 애플리케이션은 클라이언트 컴퓨터의 DRM 구성 요소를 업데이트할 수 있습니다. 개별화라고 하는 이 업데이트는 사용자의 애플리케이션 복사본을 동일한 애플리케이션의 다른 모든 복사본과 구분합니다. 보호된 파일의 DRM 헤더는 최소 개별화 수준을 지정할 수 있습니다. (자세한 내용은 Windows Media Rights Manager SDK의 WMRMHeader.IndividualizedVersion에 대한 설명서를 참조하세요.)

Microsoft 개인화 서비스는 사용자의 정보를 처리합니다. 따라서 애플리케이션이 개별화되기 전에 Microsoft 개인정보처리방침을 표시하거나 링크를 제공해야 합니다( Microsoft 개인정보처리방침 참조).

소프트웨어 인증서 제공

애플리케이션이 DRM 라이선스를 사용하도록 설정하려면 애플리케이션이 Filter Graph Manager에 소프트웨어 인증서 또는 키를 제공해야 합니다. 이 키는 애플리케이션에 대해 개별화된 정적 라이브러리에 포함되어 있습니다. 개별화된 라이브러리를 가져오는 방법에 대한 자세한 내용은 Windows Media Format SDK 설명서에서 필수 DRM 라이브러리 가져오기 를 참조하세요.

소프트웨어 키를 제공하려면 다음 단계를 수행합니다.

  1. 정적 라이브러리에 연결합니다.
  2. IServiceProvider 인터페이스를 구현합니다.
  3. IObjectWithSite 인터페이스에 대한 필터 그래프 관리자를 쿼리합니다.
  4. IServiceProvider 구현에 대한 포인터를 사용하여 IObjectWithSite::SetSite를 호출합니다.
  5. Filter Graph Manager는 서비스 식별자에 대한 IID_IWMReader 지정하여 IServiceProvider::QueryService를 호출합니다.
  6. QueryService 구현에서 WMCreateCertificate를 호출하여 소프트웨어 키를 만듭니다.

다음 코드는 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;
}

다음 코드는 필터 그래프 관리자에서 SetSite 를 호출하는 방법을 보여 줍니다.

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

재생 그래프 빌드

DRM으로 보호되는 ASF 파일을 재생하려면 다음 단계를 수행합니다.

  1. Filter Graph Manager를 만들고 IMediaEventEx 인터페이스를 사용하여 그래프 이벤트를 등록합니다.
  2. CoCreateInstance를 호출하여 WM ASF 판독기 필터의 새 instance 만듭니다.
  3. IFilterGraph::AddFilter를 호출하여 필터 그래프에 필터를 추가합니다.
  4. IFileSourceFilter 인터페이스에 대한 필터를 쿼리합니다.
  5. 파일의 URL 을 사용하여 IFileSourceFilter::Load 를 호출합니다.
  6. EC_WMT_EVENT 이벤트를 처리합니다.
  7. 첫 번째 EC_WMT_EVENT 이벤트에서 IServiceProvider 인터페이스에 대한 WM ASF 판독기 필터를 쿼리합니다.
  8. IServiceProvider::QueryService를 호출하여 IWMDRMReader 인터페이스에 대한 포인터를 가져옵니다.
  9. IGraphBuilder::Render를 호출하여 WM ASF 판독기 필터의 출력 핀을 렌더링합니다.

참고

DRM으로 보호된 파일을 열 때 IGraphBuilder::RenderFile 을 호출하여 필터 그래프를 만들지 마세요. WM ASF 판독기 필터는 DRM 라이선스를 획득할 때까지 다른 필터에 연결할 수 없습니다. 이 단계를 수행하려면 애플리케이션이 7~8단계에 설명된 대로 필터에서 가져와야 하는 IWMDRMReader 인터페이스를 사용해야 합니다. 따라서 필터를 만들고 그래프에 추가해야 합니다.

 

참고

애플리케이션이 EC_WMT_EVENT 이벤트를 처리해야 하므로 그래프에 WM ASF 판독기 필터를 추가하기 전에 그래프 이벤트( 1단계)에 등록해야 합니다(3단계). Load가 호출되면 이벤트가 전송됩니다(5단계).

 

다음 코드에서는 그래프를 빌드하는 방법을 보여 있습니다.

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

이전 코드에서 함수는 RenderOutputPinsWM ASF 판독 기 필터의 출력 핀을 열거하고 각 핀에 대해 IGraphBuilder::Render 를 호출합니다.

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

다음 코드는 WM ASF 판독기에서 IWMDRMReader 인터페이스에 대한 포인터를 가져오는 방법을 보여줍니다.

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

DirectShow에서 ASF 파일 읽기