Dash-Industry-Forum / dash.js

A reference client implementation for the playback of MPEG DASH via Javascript and compliant browsers.
http://reference.dashif.org/dash.js/nightly/samples/dash-if-reference-player/index.html
Other
5.11k stars 1.67k forks source link

ClearKey drm not working in dashjs but shakaplayer ok #2249

Closed Murmur closed 3 years ago

Murmur commented 6 years ago

I am testing ClearKey drm decryption and the following ShakaPlayer works in Firefox and Chrome. Dashjs player does not work and I have tried "everything". Does someone see a bug in my test page, I have tried org.w3.clearkey serverURL and clearkeys[] syntax to pass KID=KEY pair.

ShakaPlayer https://m.dtv.fi/dash/index_clearkey.html?video=1 Dashjs https://m.dtv.fi/dash/index_clearkey2.html?video=1 Mpd(drm,pssh v0) https://m.dtv.fi/dash/dasherh264/drm/manifest_clearkey.mpd Mpd(drm,pssh v1) https://m.dtv.fi/dash/dasherh264/drm2/manifest.mpd Mpd(free) https://m.dtv.fi/dash/dasherh264/manifest.mpd

EDIT: I think have found a reason and it's PSSHv0/PSSHv1 table in an init section to mess things up in dashjs player. ShakaPlayer tolerates v0 in Chrome and Firefox, also ShakaPlayer tolerates v1 in Chrome.

EDIT: pullrequest-#2318 This version works in Firefox,Chrome,Operabeta https://m.dtv.fi/dash/index_clearkey2-pr2318.html?video=14

ShakaPlayer, PSSHv0 in init, PSSHv1 in manifest: Chrome=ok, Firefox=ok https://m.dtv.fi/dash/index_clearkey.html?video=1

DashjsPlayer, PSSHv0 in init, PSSHv1 in manifest: Chrome=fail, Firefox=fail https://m.dtv.fi/dash/index_clearkey2.html?video=1

ShakaPlayer, PSSHv1 in init, PSSHv1 in manifest: Chrome=ok, Firefox=fail https://m.dtv.fi/dash/index_clearkey.html?video=12

DashjsPlayer, PSSHv1 in init, PSSHv1 in manifest: Chrome=ok, Firefox=fail https://m.dtv.fi/dash/index_clearkey2.html?video=12

Shakaplayer and DashjsPlayer play non-protected video: Chrome=ok, Firefox=ok https://m.dtv.fi/dash/index_clearkey.html?video=2 https://m.dtv.fi/dash/index_clearkey2.html?video=2


Console logs from Chrome dashjs test page using LAURL address.

Navigated to https://m.dtv.fi/dash/index_clearkey2.html
Debug.js:112 [16] [dash.js 2.6.2] MediaPlayer has been initialized 
Debug.js:112 [24] EME detected on this user agent! (ProtectionModel_21Jan2015) 
Debug.js:112 [43] Playback Initialized 
Debug.js:112 [141] Parsing complete: ( xml2json: 17.5ms, objectiron: 8.69ms, total: 0.0262s) 
Debug.js:112 [161] SegmentTimeline detected using calculated Live Edge Time 
Debug.js:112 [175] MediaSource attached to element.  Waiting on open... 
Debug.js:112 [176] Manifest has been refreshed at Tue Oct 24 2017 12:53:07 GMT+0300 (FLE Daylight Time)[1508838787.597]  
Debug.js:112 [178] MediaSource is open! 
Debug.js:112 [179] Duration successfully set to: 90.005 
Debug.js:112 [181] Added 0 inline events 
Debug.js:112 [185] video codec: video/mp4;codecs="avc1.4d4028" 
Debug.js:112 [232] audio codec: audio/mp4;codecs="mp4a.40.2" 
Debug.js:112 [237] No text data. 
Debug.js:112 [237] No fragmentedText data. 
Debug.js:112 [238] No embeddedText data. 
Debug.js:112 [239] No muxed data. 
Debug.js:112 [250] Schedule controller starting for video 
Debug.js:112 [251] Schedule controller starting for audio 
Debug.js:112 [251] Start Event Controller 
Debug.js:112 [253] DRM: KeySystem Access Granted (org.w3.clearkey)!  Selecting key system... 
Debug.js:112 [254] Native video element event: play 
Debug.js:112 [258] ScheduleController - getNextFragment 
Debug.js:112 [258] ScheduleController - switch track has been asked, get init request for video with representationid = v1 
Debug.js:112 [263] ScheduleController - getNextFragment 
Debug.js:112 [264] ScheduleController - switch track has been asked, get init request for audio with representationid = a1 
Debug.js:112 [269] DRM: Session created.  SessionID = 0B986F0423000000 
Debug.js:112 [271] DRM: onKeyMessage 
Debug.js:112 [273] Failed to retrieve clearkeys from ProtectionData 
Debug.js:112 [312] Init fragment finished loading saving to video's init cache 
Debug.js:112 [318] DRM: onNeedKey 
Debug.js:112 [319] DRM: initData:   &pssh    šðy˜@B†«’æ[àˆ_•      ü< W R M H E A D E R   x m l n s = " h t t p : / / s c h e m a s . m i c r o s o f t . c o m / D R M / 2 0 0 7 / 0 3 / P l a y R e a d y H e a d e r "   v e r s i o n = " 4 . 0 . 0 . 0 " > < D A T A > < P R O T E C T I N F O > < K E Y L E N > 1 6 < / K E Y L E N > < A L G I D > A E S C T R < / A L G I D > < / P R O T E C T I N F O > < K I D > e F Y h Q z Q S N B I S N B I 0 E j Q S N A = = < / K I D > < C H E C K S U M > m u h j T 9 u C a s s = < / C H E C K S U M > < / D A T A > < / W R M H E A D E R >    4pssh    íyÖJΣÈ'ÜÕ!í   C!Vx444444   8pssh    iù¯HFê‘Í]ÌË
:      marl   mkid           4pssh    wïìÀ²M¬ã<RâûK      C!Vx444444 
Debug.js:112 [321] DRM: KeySystem Access Granted 
Debug.js:112 [323] Error generating key request -- NotSupportedError 
Debug.js:112 [326] Schedule controller stopping for video 
Debug.js:112 [328] Schedule controller stopping for audio 
Debug.js:112 [329] Native video element event: pause 

Console logs from Chrome dashjs test page using embedded clearkey property.

Navigated to https://m.dtv.fi/dash/index_clearkey2.html
Debug.js:112 [17] [dash.js 2.6.2] MediaPlayer has been initialized 
Debug.js:112 [25] EME detected on this user agent! (ProtectionModel_21Jan2015) 
Debug.js:112 [42] Playback Initialized 
Debug.js:112 [152] Parsing complete: ( xml2json: 21.6ms, objectiron: 9.16ms, total: 0.0307s) 
Debug.js:112 [164] SegmentTimeline detected using calculated Live Edge Time 
Debug.js:112 [174] MediaSource attached to element.  Waiting on open... 
Debug.js:112 [176] Manifest has been refreshed at Tue Oct 24 2017 12:55:19 GMT+0300 (FLE Daylight Time)[1508838919.1]  
Debug.js:112 [178] MediaSource is open! 
Debug.js:112 [179] Duration successfully set to: 90.005 
Debug.js:112 [182] Added 0 inline events 
Debug.js:112 [185] video codec: video/mp4;codecs="avc1.4d4028" 
Debug.js:112 [220] audio codec: audio/mp4;codecs="mp4a.40.2" 
Debug.js:112 [224] No text data. 
Debug.js:112 [224] No fragmentedText data. 
Debug.js:112 [225] No embeddedText data. 
Debug.js:112 [225] No muxed data. 
Debug.js:112 [232] Schedule controller starting for video 
Debug.js:112 [233] Schedule controller starting for audio 
Debug.js:112 [234] Start Event Controller 
Debug.js:112 [236] DRM: KeySystem Access Granted (org.w3.clearkey)!  Selecting key system... 
Debug.js:112 [237] Native video element event: play 
Debug.js:112 [246] ScheduleController - getNextFragment 
Debug.js:112 [246] ScheduleController - switch track has been asked, get init request for video with representationid = v1 
Debug.js:112 [253] ScheduleController - getNextFragment 
Debug.js:112 [254] ScheduleController - switch track has been asked, get init request for audio with representationid = a1 
Debug.js:112 [259] DRM: Session created.  SessionID = EB4C3F7527000000 
Debug.js:112 [261] DRM: onKeyMessage 
Debug.js:112 [263] DRM: ClearKey license request handled by application! 
Debug.js:112 [299] Init fragment finished loading saving to video's init cache 
Debug.js:112 [305] DRM: onNeedKey 
Debug.js:112 [306] DRM: initData:   &pssh    šðy˜@B†«’æ[àˆ_•      ü< W R M H E A D E R   x m l n s = " h t t p : / / s c h e m a s . m i c r o s o f t . c o m / D R M / 2 0 0 7 / 0 3 / P l a y R e a d y H e a d e r "   v e r s i o n = " 4 . 0 . 0 . 0 " > < D A T A > < P R O T E C T I N F O > < K E Y L E N > 1 6 < / K E Y L E N > < A L G I D > A E S C T R < / A L G I D > < / P R O T E C T I N F O > < K I D > e F Y h Q z Q S N B I S N B I 0 E j Q S N A = = < / K I D > < C H E C K S U M > m u h j T 9 u C a s s = < / C H E C K S U M > < / D A T A > < / W R M H E A D E R >    4pssh    íyÖJΣÈ'ÜÕ!í   C!Vx444444   8pssh    iù¯HFê‘Í]ÌË
:      marl   mkid           4pssh    wïìÀ²M¬ã<RâûK      C!Vx444444 
Debug.js:112 [307] DRM: KeySystem Access Granted 
Debug.js:112 [309] Error generating key request -- NotSupportedError 
Debug.js:112 [311] Schedule controller stopping for video 
Debug.js:112 [312] Schedule controller stopping for audio 
Debug.js:112 [314] Native video element event: pause 

Manifest

<?xml version="1.0" encoding="UTF-8"?>
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:cenc="urn:mpeg:cenc:2013" xmlns:mas="urn:marlin:mas:1-0:services:schemas:mpd" xmlns:mspr="urn:microsoft:playready" maxSegmentDuration="PT0H0M6.000S" mediaPresentationDuration="PT0H1M30.005S" minBufferTime="PT3.000S" profiles="urn:mpeg:dash:profile:isoff-live:2011,http://dashif.org/guidelines/dash264,urn:hbbtv:dash:profile:isoff-live:2012" type="static">

 <Period duration="PT0H1M30.005S" id="p0">
  <AdaptationSet lang="und" maxFrameRate="25" maxHeight="1080" maxWidth="1920" par="16:9" segmentAlignment="true" startWithSAP="1">
   <SegmentTemplate initialization="$RepresentationID$_i.mp4" media="$RepresentationID$_$Number$.m4s" startNumber="1" timescale="1000">
    <SegmentTimeline>
     <S d="6000" r="14" t="0"/>
    </SegmentTimeline>
   </SegmentTemplate>
   <ContentProtection cenc:default_KID="43215678-1234-1234-1234-123412341234" schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc"/>
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b">
  <cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAFDIVZ4EjQSNBI0EjQSNBI0AAAAAA==</cenc:pssh>
</ContentProtection>
   <Representation bandwidth="491871" codecs="avc1.4d4028" frameRate="25" height="360" id="v1" mimeType="video/mp4" sar="1:1" width="640">
   </Representation>
   <Representation bandwidth="1411922" codecs="avc1.4d4028" frameRate="25" height="720" id="v2" mimeType="video/mp4" sar="1:1" width="1280">
   </Representation>
   <Representation bandwidth="1955820" codecs="avc1.4d4028" frameRate="25" height="1080" id="v3" mimeType="video/mp4" sar="1:1" width="1920">
   </Representation>
  </AdaptationSet>
  <AdaptationSet lang="und" segmentAlignment="true" startWithSAP="1">
   <SegmentTemplate initialization="$RepresentationID$_i.mp4" media="$RepresentationID$_$Number$.m4s" startNumber="1" timescale="1000">
    <SegmentTimeline>
     <S d="5973" t="0"/>
     <S d="5995" r="1"/>
     <S d="5994"/>
     <S d="5995" r="1"/>
     <S d="5994"/>
     <S d="5995"/>
     <S d="5994"/>
     <S d="5995" r="2"/>
     <S d="5994"/>
     <S d="5995" r="1"/>
     <S d="106"/>
    </SegmentTimeline>
   </SegmentTemplate>
   <ContentProtection cenc:default_KID="43215678-1234-1234-1234-123412341234" schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc"/>
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b">
  <cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAFDIVZ4EjQSNBI0EjQSNBI0AAAAAA==</cenc:pssh>
</ContentProtection>
   <Representation audioSamplingRate="48000" bandwidth="136244" codecs="mp4a.40.2" id="a1" mimeType="audio/mp4">
    <AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
   </Representation>
  </AdaptationSet>
 </Period>
</MPD>

ClearKey license url script is using a different url syntax in Shaka and Dashjs, this script handles both formats and returns a json kid-key pair. https://m.dtv.fi/dash/laurl_ck.php

SkahaPlayer POST
POST: {"kids":["QyFWeBI0EjQSNBI0EjQSNA"],"type":"temporary"}
REPLY: {"keys": [{"k": "EjQSNBI0EjQSNBI0EjQSNA", "kty": "oct", "kid": "QyFWeBI0EjQSNBI0EjQSNA" }], "type": "temporary"}

Dashjs GET
GET: https://m.dtv.fi/dash/laurl_ck.php?/?QyFWeBI0EjQSNBI0EjQSNA
REPLY:  {"keys": [{"k": "EjQSNBI0EjQSNBI0EjQSNA", "kty": "oct", "kid": "QyFWeBI0EjQSNBI0EjQSNA" }], "type": "temporary"}

Dashjs script in index_clearkey2.html page

   function initApp() {
      var player = dashjs.MediaPlayer().create();
      player.initialize();
      player.setAutoPlay(true);
      player.setProtectionData({
         "org.w3.clearkey": { "serverURL" : laUrl }
         //"org.w3.clearkey": { "clearkeys": { "QyFWeBI0EjQSNBI0EjQSNA":"EjQSNBI0EjQSNBI0EjQSNA" } } // KID=KEY
      });
      player.attachView( document.querySelector("#video") );            
      player.attachSource(manifestUrl);
   }

   document.addEventListener('DOMContentLoaded', initApp);
davemevans commented 6 years ago

The cenc pssh box in your initialisation segment is incorrect - it does not conform to https://www.w3.org/TR/eme-initdata-cenc/ (it appears to be using v0 pssh boxes). This causes the call to MediaKeySession.generateRequest to fail with DOMException: No supported PSSH box found.

The pssh in the manifest is correct but is not being used which is possibly a bug - it should maybe be appended to the segment initialisation data - but the spec only states may so this could be interpreted in a number of ways. Perhaps shaka does something different here.

I can get the content to play by modifying the pssh to be compliant with the specification.

Init Seg:

00 00 00 34 70 73 73 68
00 00 00 00 10 77 ef ec 
c0 b2 4d 02 ac e3 3c 1e
52 e2 fb 4b 00 00 00 14
00 00 00 01 43 21 56 78 
12 34 12 34 12 34 12 34
12 34 12 34

MPD

00 00 00 34 70 73 73 68 
01 00 00 00 10 77 ef ec
c0 b2 4d 02 ac e3 3c 1e
52 e2 fb 4b 00 00 00 01
43 21 56 78 12 34 12 34
12 34 12 34 12 34 12 34
00 00 00 00
Murmur commented 6 years ago

@bbcrddave Than you and I found the source of the problem about the same time. I edited my question and also added few more ?video=1..n test cases to be run. Reason ShakaPlayer works must be the fact it's using field from the manifest so incorrent version number in an init/PSSH did not matter.

I have always used PSSHver=0 for Playready,Marlin,Widevine DRM systems. This was incorrent version field for 1077efec-c0b2-4d02-ace3-3c1e52e2fb4b pssh table data.

epiclabsDASH commented 6 years ago

Interesting conversation. Let's keep this open until we investigate what @bbcrddave mentioned regarding the spec and what dash.js should do in these cases.

davemevans commented 6 years ago

Looks from some relevant specifiations that there might be an issue in dash.js here:

The DVB specification is also explicit (section 8.5.0):

For each DRM SystemID, if DRM specific data is present both within a 'pssh' box in the initialization segment and within a Content Protection descriptor in the MPD, the data within each should carry equivalent information. However, the data carried within the MPD takes precedence over the data carried within the 'pssh'.

Murmur commented 6 years ago

Heads up, I compiled a fresh ffmpeg.exe+mp4box.exe tools, repackaged a test video and updated manifest+pssh use cases. Looking better now, I generated 1077efecc0b24d02ace33c1e52e2fb4b version PSSHv1 to both init.mp4 and manifest fields. Also something must have been fixed in mp4box segmentation tool because had problems with Widevine+Firefox but it's now fine in dashjs player.

Shaka https://m.dtv.fi/dash/index_clearkey.html?video=21 Dashjs https://m.dtv.fi/dash/index_clearkey2.html?video=21 Use ?video=2f to playback nodrm(free) manifest. Mpd clearkey https://m.dtv.fi/dash/dasherh264v2/drm/manifest_clearkey.mpd Mpd free https://m.dtv.fi/dash/dasherh264v2/manifest.mpd LaUrl server https://m.dtv.fi/dash/laurl_ck.php

Shaka: Chrome=ok, Firefox=ok, Operabeta=ok (all on Win10) Dashjs: Chrome=ok, Firefox=ok, Operabeta=ok (all on Win10)

epiclabsDASH commented 6 years ago

Many thanks!

@Murmur, is it possible that you share with me the content of the first streams you generated (PSSHV0 and PSSHV1) and that didn't work with Dash.js player? I would like to take a look and fix the issue in dash.js.

As pointed out by @bbcrddave, according to spec, although pssh box of initialization segment is wrong they should work if pssh of the manifest is correct.

Murmur commented 6 years ago

@epiclabsDASH Download zipped folders, you should find nodrm(free), encrypted segments in drm/* subfolder and manifest files. Use dasherh264/drm/manifest_clearkey.mpd where init=psshv0 and manifest=psshv1. Use drm/manifest.mpd for playready testing if that is an interest.

https://m.dtv.fi/dash/dasherh264.zip (3xh264, 1xaac) https://m.dtv.fi/dash/dasherh264v2.zip (1xh264, 1xaac)

For reference this is an encryption KID+KEY pair and also Microsoft Playready laurl test address. You may want to use an embedded clearkey KID+KEY for testing.

"key": "12341234123412341234123412341234"
"kid": "43215678123412341234123412341234"
"playready": "https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(kid:header,sl:2000,persist:false,firstexp:60,contentkey:EjQSNBI0EjQSNBI0EjQSNA==)"
epiclabsDASH commented 6 years ago

Many thanks, really appreciated.

epiclabsDASH commented 6 years ago

@Murmur, I am closing this issue as this problem seems to be fixed. There is pending work related with ClearKey (license server integration) but will be handle in a specific issue for it.

dovelive commented 6 years ago

Hi. @Murmur

I have a question on this issue. Is that possible to play the encrypted drm stream using dash.js and clearkey only? For example, I made the test html based on your example html code.

Here is the code.

<!doctype html>
<html>
    <head>
        <title>Dash.js Rocks</title>
    </head>
        <style>
            video {
                width: 640px;
                height: 360px;
            }
        </style>
    <body>
        <div>
            <video id="video" controls></video>
        </div>
<!--        <script src="js/dash.all.debug.js"></script>-->
        <script src="https://cdn.dashjs.org/latest/dash.all.debug.js"></script>
        <script>
            (function(){
          var url = "https://m.dtv.fi/dash/dasherh264v2/drm/manifest_clearkey.mpd";
        var laUrl       = 'https://m.dtv.fi/dash/laurl_ck.php?';

            var player = dashjs.MediaPlayer().create();
            player.setProtectionData({
//              "org.w3.clearkey": { "serverURL" : laUrl }
                "org.w3.clearkey": { "clearkeys": { "43215678123412341234123412341234":"EjQSNBI0EjQSNBI0EjQSNA" } } 
            });
            player.initialize(document.querySelector("#video"), url, false);

            })();
        </script>
    </body>
</html>

However it does not work and gives me the error below.

Debug.js:236 [518][Stream] Error generating key request -- TypeError 

I tried to change some parameters, but I couldn't play that stream using dash.js. So I am wondering if that error is because of dash.js itself or my usage mistake.

Is that possible to play the drm stream using dash.js and clearkey only(not using laUrl)?

Would you like to help me to answer my question? Regards.

Murmur commented 6 years ago

Please see this bug report it may be a bug in a current Dashjs player release. https://github.com/Dash-Industry-Forum/dash.js/issues/2687

dovelive commented 6 years ago

It seems so. It works with the laUrl, but not working with clearkey kid/key pair.

epiclabsDASH commented 6 years ago

Taking a look. I will get back to you asap.

dovelive commented 6 years ago

Hi. @epiclabsDASH Any update for this error?

epiclabsDASH commented 6 years ago

Hi @dovelive!

This issue was fixed in #2318 although there was a recent regression. Issue should be fixed in #2770.

Thanks!

bbert commented 5 years ago

Hi @epiclabsDASH and @Murmur, I reopen this issue since we have an issue with the way it has been resolved in #PR2318. Can someone explain me what is the logic in the code of this ProtectionKeyController's function?:

function getSupportedKeySystemsFromContentProtection(cps) {
    let cp, ks, ksIdx, cpIdx;
    let supportedKS = [];

    if (cps) {
        for (ksIdx = 0; ksIdx < keySystems.length; ++ksIdx) {
            ks = keySystems[ksIdx];
            for (cpIdx = 0; cpIdx < cps.length; ++cpIdx) {
                cp = cps[cpIdx];
                if (cp.schemeIdUri.toLowerCase() === ks.schemeIdURI) {
                    // Look for DRM-specific ContentProtection
                    let initData = ks.getInitData(cp);
                    if (!!initData) {
                        supportedKS.push({
                            ks: keySystems[ksIdx],
                            initData: initData,
                            cdmData: ks.getCDMData(),
                            sessionId: ks.getSessionId(cp)
                        });
                    } else if (this.isClearKey(ks)) {
                        supportedKS.push({
                            ks: ks,
                            initData: null
                        });
                    }
                }
            }
        }
    }
    return supportedKS;
}

We have an issue in the case we want to select a key system from content protection data in which we do not provide initData but only for example the MediaKeySession id. The scenario is to use dash.js to load and then remove Widevine persistent sessions. When removing a persistent session, we do not have anymore the initData but only the session id. Then, as it is, the getSupportedKeySystemsFromContentProtection() would return no key system, thus disabling selecting a key system in ProtectionController.initializeForMedia().

What was the issue with the previous version of this function?:

function getSupportedKeySystemsFromContentProtection(cps) {
    let cp, ks, ksIdx, cpIdx;
    let supportedKS = [];

    if (cps) {
        for (ksIdx = 0; ksIdx < keySystems.length; ++ksIdx) {
            ks = keySystems[ksIdx];
            for (cpIdx = 0; cpIdx < cps.length; ++cpIdx) {
                cp = cps[cpIdx];
                if (cp.schemeIdUri.toLowerCase() === ks.schemeIdURI) {
                    // Look for DRM-specific ContentProtection
                    supportedKS.push({
                        ks: ks,
                        initData: ks.getInitData(cp),
                        cdmData: ks.getCDMData(),
                        sessionId: ks.getSessionId(cp)
                    });
                }
            }
        }
    }
    return supportedKS;
}
bbert commented 5 years ago

BTW @Murmur, I tested some test streams that you provided but I always manage to playback them, whatever the implementation of the getSupportedKeySystemsFromContentProtection() method. Can you provide me one sample that were not working before PR #2318?

bbert commented 5 years ago

@JohnIball or @Murmur can you provide the link to stream mentionned in issue #2769 ?

bbert commented 5 years ago

Thanks to @Johnlball I managed to do some tests. The content I tested is configured this way:

Then in its initial version, dash.js was selecting Widevine key system but then failed to get the license since the Widevine license server URL is not provided. After PR #2318, ClearKey key system is selected dut to implemented algorithm:

Then, dash.js selects ClearKey key system and manages to get license since licenser server URL is contained in ClearKey pssh from initialization segment.

I would like to be convinced this algorithm is conformed but not only adapted to this specific stream and manifest configuration.

Should we really ignore key system from MPD if pssh is missing? @davemevans @sandersaares what is your opinion?

sandersaares commented 5 years ago

I lay out my brief thoughts on DRM system activation. I completely ignore what dash.js does today in this comment (and I do not even know what it does today).

First, what is required to activate a DRM system?

To explain the last bit - in practice, 95% of the PSSHs I see are just wrappers for the key ID and contain no other useful data, which is why I consider them also synthesizable for PlayReady and Widevine. Of course, this is not a universal rule.

Which systems are even candidates? I would consider the following:

Some DRM systems require initialization data to be provided. Where can initialization data come from?

  1. The MPD provides default initialization data.
  2. This can be overridden by the API if the app chooses to do so.

How the initialization data is provided (or whether it is at all) should have no impact on DRM system preference - it just determines if the DRM system remains a candidate or not.

I would only consider using init segment data as a last resort fallback (with an appropriate warning emitted to log output). It is not something that should happen with good content. I would only use that data if none of the candidate DRM systems can be activated based on API/MPD provided initialization data. When ClearKey is a candidate, this would never be the case as ClearKey can always be activated because its initialization data can be synthesized.

I would treat config like license server URLs the same as initialization data.

It may be that multiple DRM systems can be used (e.g. Chromecast supports both PlayReady and Widevine and I guess also ClearKey). In such a situation the app should be able to select a preferred DRM system. This choice may depend on different factors both technical (e.g. desired output resolution) and nontechnical (arbitrary clauses in contracts), so the mechnaism of choice should be entirely up to the app (maybe give some callback a list of available systems and ask for order of preference). This mechanism could also be used to exclude certain DRM systems that the app does not wish to consider as valid candidates for activation.

Note that DASH-IF IOP guidelines forbid mixing of ClearKey signaling with real DRM system signaling in the same MPD. Mostly as just a precaution against exposing content keys through accidental ClearKey inclusion.

bbert commented 5 years ago

Hello @sandersaares, thanks a lot for your feedback. It confirms that the way we have implemented key system selection has not been done the right way, and that we have modified/patched the source code to map the specific stream configuration described in this thread. The initial issue was: "it works with shaka but not with dash.js". But maybe in shaka the default key system selection order is different than in dash.js. Anyway I also agree that "the mechanism of choice should be entirely up to the app". I will check if this is feasible with current API, and if dash.js is conformed to what you described.

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] commented 3 years ago

This issue has been automatically closed because no further activity occurred. If you think this issue is still relevant please reopen it. Thank you for your contributions.