PlayReady 암호화된 미디어 확장

이 섹션에서는 이전 Windows 8.1 버전에서 Windows 10 버전으로 변경된 사항을 지원하도록 PlayReady 웹 앱을 수정하는 방법에 대해 설명합니다.

Internet Explorer에서 PlayReady 미디어 요소를 사용하면 개발자가 콘텐츠 공급자가 정의한 액세스 규칙을 적용하면서 사용자에게 PlayReady 콘텐츠를 제공할 수 있는 웹앱을 만들 수 있습니다. 이 섹션에서는 HTML5 및 JavaScript만 사용하여 기존 웹앱에 PlayReady 미디어 요소를 추가하는 방법을 설명합니다.

PlayReady 암호화된 미디어 확장의 새로운 기능

이 섹션에서는 Windows 10에서 PlayReady 콘텐츠 보호를 사용하도록 설정하기 위해 EME(PlayReady 암호화 미디어 확장)에 대한 변경 내용 목록을 제공합니다.

다음 목록에서는 Windows 10용 PlayReady 암호화 미디어 확장의 새로운 기능 및 변경 내용을 설명합니다.

  • 하드웨어 DRM(디지털 권한 관리)이 추가되었습니다.

    하드웨어 기반 콘텐츠 보호 지원을 사용하면 여러 디바이스 플랫폼에서 HD(고화질) 및 UHD(초고화질) 콘텐츠를 안전하게 재생할 수 있습니다. 키 자료(프라이빗 키, 콘텐츠 키 및 해당 키를 파생하거나 잠금 해제하는 데 사용되는 기타 키 자료 포함) 및 암호 해독된 압축 및 압축되지 않은 비디오 샘플은 하드웨어 보안을 활용하여 보호됩니다.

  • 비영구 라이선스의 사전 취득을 제공합니다.

  • 하나의 메시지로 여러 라이선스 취득을 제공합니다.

    Windows 8.1에서와 같이 여러 키 식별자(KeyID)가 있는 PlayReady 개체를 사용하거나 여러 KeyID와 함께 CDMData(콘텐츠 암호 해독 모델 데이터)를 사용할 수 있습니다.

    참고 항목

    Windows 10에서는 CDMData의 <KeyID>에서 여러 키 식별자가 지원됩니다.

  • 실시간 만료 지원 또는 제한된 기간 라이선스(LDL)가 추가되었습니다.

    라이선스에 대한 실시간 만료를 설정하는 기능을 제공합니다.

  • HDCP 유형 1(버전 2.2) 정책 지원이 추가되었습니다.

  • Miracast는 이제 출력으로 암시적입니다.

  • 보안 중지가 추가되었습니다.

    보안 정지는 PlayReady 디바이스가 미디어 스트리밍 서비스에 특정 콘텐츠에 대해 미디어 재생이 중지되었음을 자신 있게 주장할 수 있는 수단을 제공합니다.

  • 오디오 및 비디오 라이선스 분리가 추가되었습니다.

    별도의 트랙은 비디오가 오디오로 디코딩되는 것을 방지합니다. 보다 강력한 콘텐츠 보호를 사용하도록 설정합니다. 새로운 표준에서는 오디오 및 시각적 트랙에 대해 별도의 키가 요구됩니다.

  • MaxResDecode가 추가되었습니다.

    이 기능은 더 유능한 키를 소유하는 경우에도 콘텐츠 재생을 최대 해상도로 제한하기 위해 추가되었습니다(라이선스는 아님). 여러 스트림 크기가 단일 키로 인코딩되는 경우를 지원합니다.

PlayReady의 암호화된 미디어 확장 지원

이 섹션에서는 PlayReady에서 지원하는 W3C 암호화 미디어 확장의 버전을 설명합니다.

Web Apps용 PlayReady는 현재 2013년 5월 10일의 W3C EME(암호화된 미디어 확장) 초안에 바인딩되어 있습니다. 이 지원은 이후 버전의 Windows에서 업데이트된 EME 사양으로 변경됩니다.

하드웨어 DRM 사용

이 섹션에서는 웹앱에서 PlayReady 하드웨어 DRM을 사용하는 방법과 보호된 콘텐츠가 지원하지 않는 경우 하드웨어 DRM을 사용하지 않도록 설정하는 방법을 설명합니다.

PlayReady 하드웨어 DRM을 사용하려면 JavaScript 웹앱이 브라우저에서 PlayReady 하드웨어 DRM 지원을 쿼리할 키 com.microsoft.playready.hardware 시스템 식별자와 함께 isTypeSupported EME 메서드를 사용해야 합니다.

간혹 일부 콘텐츠는 하드웨어 DRM에서 지원되지 않는 경우가 있습니다. 칵테일 콘텐츠는 하드웨어 DRM에서 지원되지 않습니다. 칵테일 콘텐츠를 재생하려면 하드웨어 DRM을 옵트아웃해야 합니다. 일부 하드웨어 DRM은 HEVC를 지원하며 일부는 지원하지 않습니다. HEVC 콘텐츠를 재생하고 하드웨어 DRM에서 지원하지 않는 경우 옵트아웃(opt out)할 수도 있습니다.

참고 항목

HEVC 콘텐츠가 지원되는지 여부를 확인하려면 com.microsoft.playready 인스턴스화한 후 PlayReadyStatics.CheckSupportedHardware 메서드를 사용합니다.

웹앱에 보안 중지 추가

이 섹션에서는 웹 앱에 보안 정지를 추가하는 방법에 대해 설명합니다.

보안 정지는 PlayReady 디바이스가 미디어 스트리밍 서비스에 특정 콘텐츠에 대해 미디어 재생이 중지되었음을 자신 있게 주장할 수 있는 수단을 제공합니다. 이 기능을 사용하면 미디어 스트리밍 서비스에서 특정 계정에 대해 여러 디바이스에서 사용 제한을 정확하게 적용하고 보고할 수 있습니다.

보안 중지 챌린지를 보내는 두 가지 주요 시나리오가 있습니다.

  • 콘텐츠의 끝에 도달했거나 사용자가 중간 어딘가에 미디어 프레젠테이션을 중지한 경우 미디어 프레젠테이션이 중지되는 경우
  • 이전 세션이 예기치 않게 종료되는 경우(예: 시스템 또는 앱 크래시로 인해) 앱은 시작 또는 종료 시 미해결 보안 중지 세션을 쿼리하고 다른 미디어 재생과 별도로 챌린지를 보내야 합니다.

다음 절차에서는 다양한 시나리오에 대한 보안 중지를 설정하는 방법을 설명합니다.

프레젠테이션의 정상적인 종료에 대한 보안 중지를 설정하려면 다음을 수행합니다.

  1. 재생이 시작되기 전에 onEnded 이벤트를 등록합니다.
  2. onEnded 이벤트 처리기는 비디오/오디오 요소 개체에서 removeAttribute("src") 호출하여 원본을 NULL로 설정해야 합니다. 이 개체는 미디어 파운데이션을 트리거하여 토폴로지 분해, 암호 해독기 삭제 및 중지 상태를 설정합니다.
  3. 처리기 내에서 보안 중지 CDM 세션을 시작하여 서버에 보안 중지 챌린지를 보내 재생이 중지되었음을 알릴 수 있지만 나중에 수행할 수도 있습니다.

사용자가 페이지에서 벗어나거나 탭 또는 브라우저를 닫는 경우 보안 중지를 설정하려면 다음을 수행합니다.

  • 중지 상태를 기록하는 데 필요한 앱 작업은 없습니다. 그것은 당신을 위해 기록됩니다.

사용자 지정 페이지 컨트롤 또는 사용자 작업(예: 사용자 지정 탐색 단추 또는 현재 프레젠테이션이 완료되기 전에 새 프레젠테이션 시작)에 대한 보안 중지를 설정하려면 다음을 수행합니다.

  • 사용자 지정 사용자 작업이 발생하면 앱은 원본을 NULL로 설정해야 합니다. 이 소스는 미디어 파운데이션을 트리거하여 토폴로지 분해, 암호 해독기 삭제 및 중지 상태를 설정합니다.

다음 예제에서는 웹앱에서 보안 중지를 사용하는 방법을 보여 줍니다.

// JavaScript source code

var g_prkey = null;
var g_keySession = null;
var g_fUseSpecificSecureStopSessionID = false;
var g_encodedMeteringCert = 'Base64 encoded of your metering cert (aka publisher cert)';

// Note: g_encodedLASessionId is the CDM session ID of the proactive or reactive license acquisition 
//       that we want to initiate the secure stop process.
var g_encodedLASessionId = null;

function main()
{
    ...

    g_prkey = new MSMediaKeys("com.microsoft.playready");

    ...

    // add 'onended' event handler to the video element
    // Assume 'myvideo' is the ID of the video element
    var videoElement = document.getElementById("myvideo");
    videoElement.onended = function (e) { 

        //
        // Calling removeAttribute("src") will set the source to null
        // which will trigger the MF to tear down the topology, destroy the
        // decryptor(s) and set the stop state.  This is required in order
        // to set the stop state.
        //
        videoElement.removeAttribute("src");
        videoElement.load();

        onEndOfStream();
    };
}

function onEndOfStream()
{
    ...

    createSecureStopCDMSession();

    ...    
}

function createSecureStopCDMSession()
{
    try{    
        var targetMediaCodec = "video/mp4";
        var customData = "my custom data";

        var encodedSessionId = g_encodedLASessionId;
        if( !g_fUseSpecificSecureStopSessionID )
        {
            // Use "*" (wildcard) as the session ID to include all secure stop sessions
            // TODO: base64 encode "*" and place encoded result to encodedSessionId
        }

        var int8ArrayCDMdata = formatSecureStopCDMData( encodedSessionId, customData,  g_encodedMeteringCert );
        var emptyArrayofInitData = new Uint8Array();

        g_keySession = g_prkey.createSession(targetMediaCodec, emptyArrayofInitData, int8ArrayCDMdata);

        addPlayreadyKeyEventHandler();

    } catch( e )
    {
        // TODO: Handle exception
    }
}

function addPlayreadyKeyEventHandler()
{
    // add 'keymessage' eventhandler   
    g_keySession.addEventListener('mskeymessage', function (event) {

        // TODO: Get the keyMessage from event.message.buffer which contains the secure stop challenge
        //       The keyMessage format for the secure stop is similar to LA as below:
        //
        //            <PlayReadyKeyMessage type="SecureStop" >
        //              <SecureStop version="1.0" >
        //                <Challenge encoding="base64encoded">
        //                    secure stop challenge
        //                </Challenge>
        //                <HttpHeaders>
        //                    <HttpHeader>
        //                      <name>Content-Type</name>
        //                         <value>"content type data"</value>
        //                    </HttpHeader>
        //                    <HttpHeader>
        //                         <name>SOAPAction</name>
        //                         <value>soap action</value>
        //                     </HttpHeader>
        //                    ....
        //                </HttpHeaders>
        //              </SecureStop>
        //            </PlayReadyKeyMessage>
                
        // TODO: send the secure stop challenge to a server that handles the secure stop challenge

        // TODO: Receive and response and call event.target.Update() to proecess the response
    });
    
    // add 'keyerror' eventhandler
    g_keySession.addEventListener('mskeyerror', function (event) {
        var session = event.target;
        
        ...

        session.close();
    });
    
    // add 'keyadded' eventhandler
    g_keySession.addEventListener('mskeyadded', function (event) {
        
        var session = event.target;

        ...

        session.close();             
    });
}

/**
* desc@ formatSecureStopCDMData
*   generate playready CDMData
*   CDMData is in xml format:
*   <PlayReadyCDMData type="SecureStop">
*     <SecureStop version="1.0">
*       <SessionID>B64 encoded session ID</SessionID>
*       <CustomData>B64 encoded custom data</CustomData>
*       <ServerCert>B64 encoded server cert</ServerCert>
*     </SecureCert>
* </PlayReadyCDMData>        
*/
function formatSecureStopCDMData(encodedSessionId, customData, encodedPublisherCert) 
{
    var encodedCustomData = null;

    // TODO: base64 encode the custom data and place the encoded result to encodedCustomData

    var CDMDataStr = "<PlayReadyCDMData type=\"SecureStop\">" +
                     "<SecureStop version=\"1.0\" >" +
                     "<SessionID>" + encodedSessionId + "</SessionID>" +
                     "<CustomData>" + encodedCustomData + "</CustomData>" +
                     "<ServerCert>" + encodedPublisherCert + "</ServerCert>" +
                     "</SecureStop></PlayReadyCDMData>";
    
    var int8ArrayCDMdata = null

    // TODO: Convert CDMDataStr to Uint8 byte array and palce the converted result to int8ArrayCDMdata

    return int8ArrayCDMdata;
}

참고 항목

위의 샘플에 있는 보안 중지 데이터의 <SessionID>B64 encoded session ID</SessionID>는 기록된 모든 보안 중지 세션의 와일드 카드인 별표(*)가 될 수 있습니다. 즉 SessionID 태그는 구체적인 세션이거나 모든 보안 중지 세션을 선택하도록 와일드 카드(*)가 될 수 있습니다.

암호화된 미디어 확장에 대한 프로그래밍 고려 사항

이 섹션에서는 Windows 10용 PlayReady 사용 웹앱을 만들 때 고려해야 할 프로그래밍 고려 사항을 나열합니다.

앱에서 만든 MSMediaKeysMSMediaKeySession 개체는 앱이 닫을 때까지 활성 상태로 유지되어야 합니다. 이러한 개체를 활성 상태로 유지하는 한 가지 방법은 전역 변수로 할당하는 것입니다(변수는 범위를 벗어나고 함수 내에서 지역 변수로 선언된 경우 가비지 수집의 대상이 됩니다). 예를 들어 다음 샘플에서는 g_msMediaKeysg_mediaKeySession 변수를 전역 변수로 할당합니다. 그런 다음 해당 변수가 함수의 MSMediaKeysMSMediaKeySession 개체에 할당됩니다.

var g_msMediaKeys;
var g_mediaKeySession;

function foo() {
  ...
  g_msMediaKeys = new MSMediaKeys("com.microsoft.playready");
  ...
  g_mediaKeySession = g_msMediaKeys.createSession("video/mp4", intiData, null);
  g_mediaKeySession.addEventListener(this.KEYMESSAGE_EVENT, function (e) 
  {
    ...
    downloadPlayReadyKey(url, keyMessage, function (data) 
    {
      g_mediaKeySession.update(data);
    });
  });
  g_mediaKeySession.addEventListener(this.KEYADDED_EVENT, function () 
  {
    ...
    g_mediaKeySession.close();
    g_mediaKeySession = null;
  });
}

자세한 내용은 단일 애플리케이션을 참조하세요.

참고 항목