Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DASH: Indicate license acquisition url in mpd for clearkey content. #1197

Open
sr1990 opened this issue Apr 7, 2023 · 3 comments
Open

DASH: Indicate license acquisition url in mpd for clearkey content. #1197

sr1990 opened this issue Apr 7, 2023 · 3 comments
Labels
type: enhancement New feature or request
Milestone

Comments

@sr1990
Copy link
Contributor

sr1990 commented Apr 7, 2023

As per https://dashif.org/guidelines/iop-v5/#part-6-content-protection-and-security - 8 Use of W3C Clear Key with DASH,

A DRM system specific ContentProtection descriptor for Clear Key shall use the systemID=e2719d58-a985-
b3c9-781a-b030af78d30e and the attribute @value shall be equal to "ClearKey1.0".
The Laurl element shall be used to indicate the license server URL. The attribute @licenseType describes the type
of the license served by this license server.

Example:
MPD url: https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest_1080p_ClearKey.mpd

<ContentProtection schemeIdUri="urn:mpeg:dash:mp4protection:2011" value="cenc" cenc:default_KID="9eb4050d-e44b-4802-932e-27d75083e266" />
 <ContentProtection value="ClearKey1.0" schemeIdUri="urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e">
    <clearkey:Laurl Lic_type="EME-1.0">https://drm-clearkey-testvectors.axtest.net/AcquireLicense</clearkey:Laurl>
</ContentProtection> 

When player encounters the above ContentProtection elements,it will

  1. parse the default_KID from ContentProtection in the manifest and construct a PSSH box from it to feed to the ClearKey CDM.
  2. parse license url and send a POST request to license url as per https://w3c.github.io/encrypted-media/#clear-key-request-format to retrieve the decryption key/s.

This is already supported by shaka player, dash-if player and Android's Exoplayer.

Currently,

../packager \
  'in=Sintel-1280x720.mp4,stream=video,init_segment=h264_1280p/init.mp4,segment_template=h264_1280p/$Number$.m4s' \
  'in=Sintel-audio.mp4,stream=audio,init_segment=audioSintel/init.mp4,segment_template=audioSintel/$Number$.m4s' \
  --mpd_output cencExample1.mpd --generate_static_live_mpd \
  --enable_raw_key_encryption --enable_raw_key_decryption --clear_lead=0 \
  -key 2844832a5bfe06350dfd95caff1b6c5c -key_id 444c849e58101486ec19ceb33ec00287

will add the following to mpd:

      <ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b">
        <cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAFETISeWBAUhuwZzrM+wAKHAAAAAA==</cenc:pssh>
      </ContentProtection>

There is no way to indicate license acquisition url.

One possible solution to indicate a licence server of @licenseType EME-1.0 is to add a flag like --clear_key_license_url "https://drm-clearkey-testvectors.axtest.net/AcquireLicense".

Example:

../packager \
  'in=Sintel-1280x720.mp4,stream=video,init_segment=h264_1280p/init.mp4,segment_template=h264_1280p/$Number$.m4s' \
  'in=Sintel-audio.mp4,stream=audio,init_segment=audioSintel/init.mp4,segment_template=audioSintel/$Number$.m4s' \
  --mpd_output cencExample1.mpd --generate_static_live_mpd \
  --enable_raw_key_encryption --enable_raw_key_decryption --clear_lead=0 \
  -key 2844832a5bfe06350dfd95caff1b6c5c -key_id 444c849e58101486ec19ceb33ec00287 \
   --clear_key_license_url "https://drm-clearkey-testvectors.axtest.net/AcquireLicense"

when clear_key_license_url is present, ContentProtection element with schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b" should be skipped and <ContentProtection value="ClearKey1.0" schemeIdUri="urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e"> should be added.

@joeyparrish please let me know what you think.

@InSantoshMahto
Copy link

Hi @sr1990 i am also exploring same license server option

@cosmin
Copy link
Collaborator

cosmin commented Apr 26, 2024

@sr1990 that sounds like a reasonable approach, are you planning to implement this?

@cosmin cosmin added the type: enhancement New feature or request label Apr 26, 2024
@cosmin cosmin added this to the v3.1 milestone Apr 26, 2024
@sr1990
Copy link
Contributor Author

sr1990 commented Apr 29, 2024

Hey @cosmin, for the above approach I can think of the following steps:

  1. Add flag after https://github.com/shaka-project/shaka-packager/blob/main/packager/mpd/base/xml/xml_node.cc#L36
ABSL_FLAG(std::string,
          clear_key_license_url,
          "",
          "Clear key license url.");

Declare the flag after

ABSL_DECLARE_FLAG(bool, dash_add_last_segment_number_when_needed);

ABSL_DECLARE_FLAG(std::string, clear_key_license_url);
  1. In RepresentationBaseXmlNode::AddContentProtectionElement, if content protection element's scheme_id_uri == "urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b" and clear key license url is available,
    substitute the raw key's ContentProtection element with clearkey's ContentProtection element.
    Example:
 if (content_protection_element.scheme_id_uri == "urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b" &&
	!absl::GetFlag(FLAGS_clear_key_license_url).empty()) {
            
      // Create ContentProtectionElement
      ContentProtectionElement temp1;
      temp1.value = "ClearKey1.0";
      temp1.scheme_id_uri = "urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e";
 

      // Create element Clearkey
      Element clearkey;
      clearkey.name = "clearkey:Laurl";
      clearkey.content = absl::GetFlag(FLAGS_clear_key_license_url);
      clearkey.attributes["Lic_type"] = "EME-1.0";
      // Push element into contentProtectionElement
      temp1.subelements.push_back(clearkey);

      // Create ContentProtection node.
      XmlNode content_protection_temp("ContentProtection");
  	// @value is an optional attribute.
  	if (!temp1.value.empty()) {
    		RCHECK(content_protection_temp.SetStringAttribute(
        		"value", temp1.value));
  	}
  	RCHECK(content_protection_temp.SetStringAttribute(
      		"schemeIdUri", temp1.scheme_id_uri));
  
	RCHECK(content_protection_temp.AddElements(
          temp1.subelements));
      
      return AddChild(std::move(content_protection_temp));
 }  

Also a better approach would be to create ClearKeyKeySource similar to WidevineKeySource and add a flag to enable clearkey encryption --enable_clear_key_encryption

When the packager parameters are parsed at

if (absl::GetFlag(FLAGS_enable_widevine_encryption)) {
in packager_main.cc::GetPackagingParams(), set the key provider to Clearkey.
and while creating encryption key source at
internal->encryption_key_source = CreateEncryptionKeySource(

in Packager::Initialize, create and fetch keys using ClearKeyKeySource.
For fetching the keys, ClearKeyKeySource needs to send the POST request for each/all variant to the clear key license server as per
https://w3c.github.io/encrypted-media/#clear-key-request-format.

I can think of the following scenarios:

  1. Keyid and key same for all the variants - No need to fetch keys from clearkey license server
   packager \
  'in=Sintel-1280x720.mp4,stream=video,init_segment=h264_1280p/init.mp4,segment_template=h264_1280p/$Number$.m4s' \
  'in=Sintel-768x432.mp4,stream=video,init_segment=h264_768p/init.mp4,segment_template=h264_768p/$Number$.m4s' \
  'in=Sintel-audio.mp4,stream=audio,init_segment=audioSintel/init.mp4,segment_template=audioSintel/$Number$.m4s' \
  --mpd_output h264SintelRaw.mpd --generate_static_live_mpd \
  --enable_clear_key_encryption --clear_lead=0 \
  -key 2844832a5bfe06350dfd95caff1b6c5c -key_id 444c849e58101486ec19ceb33ec00287 \
  --clear_key_license_url "http://xyz/AcquireLicense"
  1. Keyid given and key needs to be fetched from the clearkey license url server
 packager \
'in=Sintel-1280x720.mp4,stream=video,init_segment=h264_1280p/init.mp4,segment_template=h264_1280p/$Number$.m4s' \
'in=Sintel-768x432.mp4,stream=video,init_segment=h264_768p/init.mp4,segment_template=h264_768p/$Number$.m4s' \
'in=Sintel-audio.mp4,stream=audio,init_segment=audioSintel/init.mp4,segment_template=audioSintel/$Number$.m4s' \
--mpd_output h264SintelRaw.mpd --generate_static_live_mpd \
--enable_clear_key_encryption --clear_lead=0 \
-key_id 444c849e58101486ec19ceb33ec00287 \
--clear_key_license_url "http://xyz/AcquireLicense"
  1. Using drm_label where key_id and key are given: no need to fetch keys from clearkey license server.
$ packager \
  in=h264_baseline_360p_600.mp4,stream=audio,output=audio.mp4,drm_label=AUDIO \
  in=h264_baseline_360p_600.mp4,stream=video,output=h264_360p.mp4,drm_label=SD \
  in=h264_main_480p_1000.mp4,stream=video,output=h264_480p.mp4,drm_label=SD \
  in=h264_main_720p_3000.mp4,stream=video,output=h264_720p.mp4,drm_label=HD \
  in=h264_high_1080p_6000.mp4,stream=video,output=h264_1080p.mp4,drm_label=HD \
  --enable_clear_key_encryption --clear_lead=0 \
  --keys label=AUDIO:key_id=f3c5e0361e6654b28f8049c778b23946:key=a4631a153a443df9eed0593043db7519,label=SD:key_id=abba271e8bcf552bbd2e86a434a9a5d9:key=69eaa802a6763af979e8d1940fb88392,label=HD:key_id=6d76f25cb17f5e16b8eaef6bbf582d8e:key=cb541084c99731aef4fff74500c12ead \
  --clear_key_license_url "http://xyz/AcquireLicense"\
  --mpd_output h264.mpd
  1. Using drm_label where keyid is given and key needs to fetched from licence server using ClearKeySource
 $ packager \
   in=h264_baseline_360p_600.mp4,stream=audio,output=audio.mp4,drm_label=AUDIO \
   in=h264_baseline_360p_600.mp4,stream=video,output=h264_360p.mp4,drm_label=SD \
   in=h264_main_480p_1000.mp4,stream=video,output=h264_480p.mp4,drm_label=SD \
   in=h264_main_720p_3000.mp4,stream=video,output=h264_720p.mp4,drm_label=HD \
   in=h264_high_1080p_6000.mp4,stream=video,output=h264_1080p.mp4,drm_label=HD \
   --enable_clear_key_encryption \
   --keys label=AUDIO:key_id=f3c5e0361e6654b28f8049c778b23946,label=SD:key_id=abba271e8bcf552bbd2e86a434a9a5d9,label=HD:key_id=6d76f25cb17f5e16b8eaef6bbf582d8e \
   --clear_key_license_url "http://xyz/AcquireLicense"\
   --mpd_output h264.mpd

We can start with the first approach for users who prefer avoiding the packager's license server request overhead. It's simpler to implement – just substitute the ContentProtection element.
I think we may require some time to implement the second approach. However, I'm available to review and test whenever necessary, if someone else takes on the implementation.
Please let me know what you think.

@cosmin cosmin removed this from the v3.1 milestone May 7, 2024
@github-actions github-actions bot added this to the Backlog milestone May 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants