Open seedoubleu opened 2 years ago
If by 'different DRM' you mean 'different key' then yes - you need to update the php file. This file is only a sample... it returns a single key id, and hashes it to generate the key. In a real implementation, you'd probably want to return a key id that is derived from the id of the video.
Yes,I mean 'different key'. And I tried different ways for it. In my understanding, the PHP file will generate the different 'key' and the corresponding 'kid', and encrypt the video with 'key', when play the video we need decrypt the video, so we pass 'kid' to PHP and generate the corresponding 'license'. A pair of 'key' and 'license' is not the same thing, but they have same 'kid'. Is there any mistake in my mind? What confused me is how to tell nginx-vod-module which 'key' to use, I found the attribute named "encryptionKey" and "encryptionIv" in 'mapped' mode, but I thought it just used for HLS, and there is no attribute to set 'kid'. Similarly, I try to find the way to configure 'kid' to different video when I use 'local' mode. Can you help me with these?
The idea in the sample PHP is that it will generate a kid according to some id of the media. It gets the full URL on the 'encryption' request, so it can parse the media id out of it. Since this is implementation-specific, this part is not implemented, and there's a TODO for it. In the sample, the key is just a hash of the kid with some secret string, you can of course implement something more sophisticated, but IMHO for clear-key, it's good enough.
There are 3 todos in the sample code that you need to close in order to use it in the real world -
Regarding encryptionKey/Iv, you don't need to use them here, the module will use the key returned in the JSON built by the PHP script.
Thanks erankor, I have seen the content of the PHP file, and make some change.
php file:
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST')
{
// get liense
$key1 = array('k' => '6JDXwILoGcZuYDKGNPiXgA', 'kty' => 'oct', 'kid' => 'ASNFZ4mrze8BI0VniavN7w');
$key2 = array('k' => 'XHYyt3r8i4EDVtu3HoFl1g', 'kty' => 'oct', 'kid' => 'ASNFZ4kBI0VniavN76vN7w');
$license = array('keys' => array($key1, $key2), 'type' => 'temporary');
echo str_replace('\\/', '/', json_encode($license));
header('access-control-allow-origin: *');
}
else
{
$currentUrl = $_SERVER["REQUEST_URI"];
// get key
$pssh1 = array('uuid' => '1077efec-c0b2-4d02-ace3-3c1e52e2fb4b', 'data' => 'AAAAAQEjRWeJq83vASNFZ4mrze8AAAAA');
$encrpytion1 = array('key' => '6JDXwILoGcZuYDKGNPiXgA==', 'key_id' => 'ASNFZ4mrze8BI0VniavN7w==', 'pssh' => array($pssh1));
$pssh2 = array('uuid' => '1077efec-c0b2-4d02-ace3-3c1e52e2fb4b', 'data' => 'AAAAAQEjRWeJASNFZ4mrze+rze8AAAAA');
$encrpytion2 = array('key' => 'XHYyt3r8i4EDVtu3HoFl1g==', 'key_id' => 'ASNFZ4kBI0VniavN76vN7w==', 'pssh' => array($pssh2));
if (strpos($currentUrl, 'f1') !== false)
$encrpytion = array($encrpytion1/*, $encrpytion2*/);
else
$encrpytion = array($encrpytion2);
echo str_replace('\\/', '/', json_encode($encrpytion));
}
?>
and if URL content string 'f1', GET request return key that convert from "0123456789abcdef0123456789abcdef":
[
{
"key": "6JDXwILoGcZuYDKGNPiXgA==",
"key_id": "ASNFZ4mrze8BI0VniavN7w==",
"pssh": [
{
"uuid": "1077efec-c0b2-4d02-ace3-3c1e52e2fb4b",
"data": "AAAAAQEjRWeJq83vASNFZ4mrze8AAAAA"
}
]
}
]
and if URL do not content string 'f1', GET request return key that convert from "01234567890123456789abcdefabcdef":
[
{
"key": "XHYyt3r8i4EDVtu3HoFl1g==",
"key_id": "ASNFZ4kBI0VniavN76vN7w==",
"pssh": [
{
"uuid": "1077efec-c0b2-4d02-ace3-3c1e52e2fb4b",
"data": "AAAAAQEjRWeJASNFZ4mrze+rze8AAAAA"
}
]
}
]
and POST request return licenses:
{
"keys": [
{
"k": "6JDXwILoGcZuYDKGNPiXgA",
"kty": "oct",
"kid": "ASNFZ4mrze8BI0VniavN7w"
},
{
"k": "XHYyt3r8i4EDVtu3HoFl1g",
"kty": "oct",
"kid": "ASNFZ4kBI0VniavN76vN7w"
}
],
"type": "temporary"
}
it can play successfully, but when I check manifest.mpd:
<?xml version="1.0"?>
<MPD
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:mpeg:dash:schema:mpd:2011"
xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
type="static"
mediaPresentationDuration="PT1880.979S"
minBufferTime="PT10S"
profiles="urn:mpeg:dash:profile:isoff-live:2011">
<Period>
<AdaptationSet
id="1"
segmentAlignment="true"
maxWidth="1280"
maxHeight="720"
maxFrameRate="25">
<SegmentTemplate
timescale="1000"
media="https://192.168.192.128/vod_dash/cjcwgl/flash_,hdh/,hdk/,cwgl0101.mp4.urlset/fragment-$Number$-$RepresentationID$.m4s"
initialization="https://192.168.192.128/vod_dash/cjcwgl/flash_,hdh/,hdk/,cwgl0101.mp4.urlset/init-$RepresentationID$.mp4"
duration="10000"
startNumber="1">
</SegmentTemplate>
<Representation
id="f1-v1-x3"
mimeType="video/mp4"
codecs="avc1.640029"
width="1280"
height="720"
frameRate="25"
sar="1:1"
startWithSAP="1"
bandwidth="549135">
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc"/>
<ContentProtection xmlns:cenc="urn:mpeg:cenc:2013" schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b" cenc:default_KID="01234567-8901-2345-6789-abcdefabcdef">
<cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAEBI0VniQEjRWeJq83vq83vAAAAAA==</cenc:pssh>
</ContentProtection>
</Representation>
<Representation
id="f2-v1-x3"
mimeType="video/mp4"
codecs="avc1.42c01e"
width="760"
height="428"
frameRate="25"
sar="1:1"
startWithSAP="1"
bandwidth="178233">
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc"/>
<ContentProtection xmlns:cenc="urn:mpeg:cenc:2013" schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b" cenc:default_KID="01234567-8901-2345-6789-abcdefabcdef">
<cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAEBI0VniQEjRWeJq83vq83vAAAAAA==</cenc:pssh>
</ContentProtection>
</Representation>
</AdaptationSet>
<AdaptationSet
id="2"
segmentAlignment="true">
<AudioChannelConfiguration
schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011"
value="1"/>
<SegmentTemplate
timescale="1000"
media="https://192.168.192.128/vod_dash/cjcwgl/flash_,hdh/,hdk/,cwgl0101.mp4.urlset/fragment-$Number$-$RepresentationID$.m4s"
initialization="https://192.168.192.128/vod_dash/cjcwgl/flash_,hdh/,hdk/,cwgl0101.mp4.urlset/init-$RepresentationID$.mp4"
duration="10000"
startNumber="1">
</SegmentTemplate>
<Representation
id="f1-a1-x3"
mimeType="audio/mp4"
codecs="mp4a.40.2"
audioSamplingRate="44100"
startWithSAP="1"
bandwidth="64000">
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc"/>
<ContentProtection xmlns:cenc="urn:mpeg:cenc:2013" schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b" cenc:default_KID="01234567-8901-2345-6789-abcdefabcdef">
<cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAEBI0VniQEjRWeJq83vq83vAAAAAA==</cenc:pssh>
</ContentProtection>
</Representation>
<Representation
id="f2-a1-x3"
mimeType="audio/mp4"
codecs="mp4a.40.2"
audioSamplingRate="44100"
startWithSAP="1"
bandwidth="48000">
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc"/>
<ContentProtection xmlns:cenc="urn:mpeg:cenc:2013" schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b" cenc:default_KID="01234567-8901-2345-6789-abcdefabcdef">
<cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAEBI0VniQEjRWeJq83vq83vAAAAAA==</cenc:pssh>
</ContentProtection>
</Representation>
</AdaptationSet>
</Period>
</MPD>
I can see the default_KID="01234567-8901-2345-6789-abcdefabcdef" in the ‘ContentProtection‘ field, that the different video use the same KID to encryption.
and my Request URL, the m4s file use the default name:
……
Request URL: https://192.168.192.128/vod_dash/cjcwgl/flash_,hdh/,hdk/,cwgl0101.mp4.urlset/fragment-1-f1-v1-x3.m4s
……
Request URL: https://192.168.192.128/vod_dash/cjcwgl/flash_,hdh/,hdk/,cwgl0101.mp4.urlset/fragment-67-f2-v1-x3.m4s
……
I use "if (strpos($currentUrl, 'f1') !== false)" in PHP file to select the key when encryption, but it seems not work. Is there any mistake here?
You don't get the file name part of the URL (/fragment...m4s), so you can't use 'f1', it has to be something in the path.
I change PHP , and use "basename" to get URL file name:
$clipName = basename($currentUrl,".m4s");
if (strpos($clipName, 'f1') !== false)
still not the expected result. Maybe I didn't get what you mean, Is there a simple example?
As I wrote - the module does NOT send the file name part of the request. The file name part, for example fragment-1-f1-v1-x3.m4s
changes every segment, and it doesn't make sense to have a separate DRM request for each segment...
I suggest you will just print the URL you get on the PHP to some log, and then you will see it...
Oh, thanks. Now I saw all request to PHP server is the same "https://.../dash_clear_key.php", the URL doesn't content file name, and I also found each segment has a request to PHP server. But if URL doesn't contain file name, how can I tell module to encrypt the video with the right key? I am trying adaptive bit rate, there are two video with different bit rate "flash_hdh/cwgl0101.mp4" and "flash_hdk/cwgl0101.mp4", and I want to encrypt different video with different key. I am still confused with these.
You set 'vod_drm_request_uri /dash_clear_key.php;', so that's what you get... You can add to it $uri or $vod_suburi etc.
Hi erankor, thanks for your help. I've solved my problem. The situation is as follow.
I added $vod_suburi
to vod_drm_request_uri
:
vod_drm_request_uri /dash_clear_key.php$vod_suburi;
and the Request URL to PHP server:
……
GET //dash_clear_key.php/vod_dash/cjcwgl/flash_hdh/cwgl0101.mp4 HTTP/1.0"
……
GET //dash_clear_key.php/vod_dash/cjcwgl/flash_hdk/cwgl0101.mp4 HTTP/1.0"
……
so that the PHP server can recognize the different video:
if (strpos($currentUrl, 'hdh') !== false) // just for test
and the manifest.mpd file:
<?xml version="1.0"?>
<MPD
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="urn:mpeg:dash:schema:mpd:2011"
xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 http://standards.iso.org/ittf/PubliclyAvailableStandards/MPEG-DASH_schema_files/DASH-MPD.xsd"
type="static"
mediaPresentationDuration="PT1880.979S"
minBufferTime="PT10S"
profiles="urn:mpeg:dash:profile:isoff-live:2011">
<Period>
<AdaptationSet
id="1"
segmentAlignment="true"
maxWidth="1280"
maxHeight="720"
maxFrameRate="25">
<SegmentTemplate
timescale="1000"
media="https://192.168.192.128/vod_dash/cjcwgl/flash_,hdh/,hdk/,cwgl0101.mp4.urlset/fragment-$Number$-$RepresentationID$.m4s"
initialization="https://192.168.192.128/vod_dash/cjcwgl/flash_,hdh/,hdk/,cwgl0101.mp4.urlset/init-$RepresentationID$.mp4"
duration="10000"
startNumber="1">
</SegmentTemplate>
<Representation
id="f1-v1-x3"
mimeType="video/mp4"
codecs="avc1.640029"
width="1280"
height="720"
frameRate="25"
sar="1:1"
startWithSAP="1"
bandwidth="549135">
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc"/>
<ContentProtection xmlns:cenc="urn:mpeg:cenc:2013" schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b" cenc:default_KID="01234567-89ab-cdef-0123-456789abcdef">
<cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAEBI0VniavN7wEjRWeJq83vAAAAAA==</cenc:pssh>
</ContentProtection>
</Representation>
<Representation
id="f2-v1-x3"
mimeType="video/mp4"
codecs="avc1.42c01e"
width="760"
height="428"
frameRate="25"
sar="1:1"
startWithSAP="1"
bandwidth="178233">
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc"/>
<ContentProtection xmlns:cenc="urn:mpeg:cenc:2013" schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b" cenc:default_KID="01234567-8901-2345-6789-abcdefabcdef">
<cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAEBI0VniQEjRWeJq83vq83vAAAAAA==</cenc:pssh>
</ContentProtection>
</Representation>
</AdaptationSet>
<AdaptationSet
id="2"
segmentAlignment="true">
<AudioChannelConfiguration
schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011"
value="1"/>
<SegmentTemplate
timescale="1000"
media="https://192.168.192.128/vod_dash/cjcwgl/flash_,hdh/,hdk/,cwgl0101.mp4.urlset/fragment-$Number$-$RepresentationID$.m4s"
initialization="https://192.168.192.128/vod_dash/cjcwgl/flash_,hdh/,hdk/,cwgl0101.mp4.urlset/init-$RepresentationID$.mp4"
duration="10000"
startNumber="1">
</SegmentTemplate>
<Representation
id="f1-a1-x3"
mimeType="audio/mp4"
codecs="mp4a.40.2"
audioSamplingRate="44100"
startWithSAP="1"
bandwidth="64000">
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc"/>
<ContentProtection xmlns:cenc="urn:mpeg:cenc:2013" schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b" cenc:default_KID="01234567-89ab-cdef-0123-456789abcdef">
<cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAEBI0VniavN7wEjRWeJq83vAAAAAA==</cenc:pssh>
</ContentProtection>
</Representation>
<Representation
id="f2-a1-x3"
mimeType="audio/mp4"
codecs="mp4a.40.2"
audioSamplingRate="44100"
startWithSAP="1"
bandwidth="48000">
<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc"/>
<ContentProtection xmlns:cenc="urn:mpeg:cenc:2013" schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b" cenc:default_KID="01234567-8901-2345-6789-abcdefabcdef">
<cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAEBI0VniQEjRWeJq83vq83vAAAAAA==</cenc:pssh>
</ContentProtection>
</Representation>
</AdaptationSet>
</Period>
</MPD>
hi erankor, I have a new question, when playing video each segment send a request to DRM server, if I want make the License that will expire after a period of time (like 5 minutes), or make the License just one-off. Is that feasible?
Don't know, you should probably check whatever spec defines the clear key license response. But, IMHO, it's a bit useless, because as the name "clear key" suggests, you just provide the key to the client, so nothing prevents the client from manually decrypting the content using the key, and using it indefinitely.
hi, i have some confuse with DASH DRM configuration, can you help me? The situation as follows.
I use local mode, nginx configure:
the PHP file is: "https://github.com/kaltura/nginx-vod-module/blob/master/test/dash_clear_key.php"
and the manifest for adaptive bit rate is: "https://192.168.192.128/vod_dash/,hdh/,hdk/,example.mp4.urlset/manifest.mpd"
How can I configure different DRM for "hdh/example.mp4" and "hdk/example.mp4" ? Modify the “/dash_clear_key.php” or change the mode to mapped mode? is there any simple example for that?