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

DRM: Apply different Content Key to different tracks and renditions #961

Open
qchroman opened this issue May 17, 2024 · 5 comments
Open

Comments

@qchroman
Copy link

Hello all,

As you know the Widevine team recommends packaging your content using different Content Keys i.e. different keys for Audio, SD, HD, etc. Imagine I have 3 input mp4 files - AUDIO, SD, HD, how could I apply different Content Keys to those during encryption and ensure that the tool generates a valid PSSH box that contains 3 different Key IDs that correspond to Contnet Keys used?

Is it possible with Bento4?

Thank you in advance for your answer!

@barbibulle
Copy link
Contributor

Yes, this is absolutely possible.
One way is to encrypt the files prior to combining them with the mp4dash tool (if you run mp4dash with encryption support, using --encryption-key, and specify the --debug option, you will see exactly what arguments are supplied when invoking mp4encrypt as an internal step).
The other way is directly with mp4dash by using the +key track property override syntax. You'll still need to pass in a --encryption-key option to set the global/default encryption key, even if not used (if you don't, mp4dash won't encrypt anything). The +key override value uses the same syntax as the --encryption-key option: <KID>:<KEY>.
Here's an example, encrypting two video files in a single presentation:

mp4dash --debug -f --widevine --playready --encryption-key 00000000000000000000000000000000:00000000000000000000000000000000 "[+key=000102030405060708090a0b0c0d0e0f:1BCD7CB13048487E88F87DE96E124CCB]video1.mp4" "[+key=a0a1a2a3a4a5a6a7a8a9aaabacadaeaf:68FAAD26FB334B4D8EFCE43FD56684F1]video2.mp4

(note the --encryption-key 00000000000000000000000000000000:00000000000000000000000000000000 dummy option).

@qchroman
Copy link
Author

qchroman commented May 23, 2024

oookey dokey...

First of all, thank you for the quick response. Now, we have made multiple tests and further require your assistance because it seems I can't get it right.

Test 1:

  • use mp4dash as a tool
  • use mp4s that have both video and audio tracks inside
  • use different keys

Command:

#!/bin/bash

../../bento4-linux/bin/mp4dash \
  --debug \
  -f \
  --encryption-key=00000000000000000000000000000000:00000000000000000000000000000000 \
  --widevine \
  --playready \
  --output-dir=./out \
  --mpd-name=manifest.mpd \
  "[+key=9324cf3e1a1751efc2d4877c1528319a:c8cc8d5156c8188053f3f2a3139d4156]../../content/sintel-480x204-24f-48g-370-600k-5.1-256k.mp4" \
  "[+key=ac9c7a75bfa0504043f6022694f59ae8:b7ccd5d0255b633cf5d15fbad047e2a1]../../content/sintel-720x306-24f-48g-730-1200k-5.1-256k.mp4"

Results:

  • The default_KID inside the manifest is the same for both audio and video tracks - not good
  • The playready pssh box and the playready object are version 4.0 and only contain single kid - not good
  • The pssh inside the init fragment has playready pssh that is version 4.0 and only contains single kid - not good
  • The Widevine pssh is missing from both the manifest and the init fragment - not good

Test 2:

  • use mp4dash as a tool
  • use mp4s that have both video and audio tracks inside
  • use different keys
  • tell bento4 to specifically generate pr header 4.3
  • tell bento4 to merge keys

Command:

#!/bin/bash

../../bento4-linux/bin/mp4dash \
  --debug \
  -f \
  --encryption-key=00000000000000000000000000000000:00000000000000000000000000000000 \
  --widevine \
  --playready \
  --playready-version 4.3 \
  --merge-keys \
  --output-dir=./out \
  --mpd-name=manifest.mpd \
  "[+key=9324cf3e1a1751efc2d4877c1528319a:c8cc8d5156c8188053f3f2a3139d4156]../../content/sintel-480x204-24f-48g-370-600k-5.1-256k.mp4" \
  "[+key=ac9c7a75bfa0504043f6022694f59ae8:b7ccd5d0255b633cf5d15fbad047e2a1]../../content/sintel-720x306-24f-48g-730-1200k-5.1-256k.mp4"

Results:

  • The playready pssh box and the playready object are version 4.3 and contains both kids - good
  • The pssh inside the init fragment has playready pssh that is version 4.3 but contains single kid - not good
  • The default_KID inside the manifest is the same for both audio and video tracks - not good
  • The Widevine pssh is missing from both the manifest and the init fragment - not good

Test 3:

  • use mp4dash as a tool
  • use one mp4 that is only audio
  • use one mp4 that is only video
  • use different keys
  • tell bento4 to specifically generate pr header 4.3
  • tell bento4 to merge keys

Command:

#!/bin/bash

../../bento4-linux/bin/mp4dash \
  --debug \
  -f \
  --encryption-key=00000000000000000000000000000000:00000000000000000000000000000000 \
  --widevine \
  --playready \
  --playready-version 4.3 \
  --merge-keys \
  --output-dir=./out \
  --mpd-name=manifest.mpd \
  "[+key=9324cf3e1a1751efc2d4877c1528319a:c8cc8d5156c8188053f3f2a3139d4156]../../content/sintel-480x204-24f-48g-370-600k-5.1-256k-AUDIO-ONLY-FRAG.mp4" \
  "[+key=ac9c7a75bfa0504043f6022694f59ae8:b7ccd5d0255b633cf5d15fbad047e2a1]../../content/sintel-480x204-24f-48g-370-600k-5.1-256k-VIDEO-ONLY-FRAG.mp4"

Results:

  • The playready pssh box and the playready object are version 4.3 and contains both kids - good
  • The default_KID inside the manifest is different for audio and video tracks - good
  • The pssh inside the init fragment has playready pssh that is version 4.3 but contains single kid - not good
  • The Widevine pssh is missing from both the manifest and the init fragment - not good

Test 4:

  • use mp4dash as a tool
  • use mp4s that have both video and audio tracks inside
  • use track=X to select the track
  • use different keys
  • tell bento4 to specifically generate pr header 4.3
  • tell bento4 to merge keys

Command:

#!/bin/bash

../../bento4-linux/bin/mp4dash \
  --debug \
  -f \
  --encryption-key=00000000000000000000000000000000:00000000000000000000000000000000 \
  --widevine \
  --playready \
  --playready-version 4.3 \
  --merge-keys \
  --output-dir=./out \
  --mpd-name=manifest.mpd \
  "[+key=9324cf3e1a1751efc2d4877c1528319a:c8cc8d5156c8188053f3f2a3139d4156,track=1]../../content/sintel-480x204-24f-48g-370-600k-5.1-256k.mp4" \
  "[+key=ac9c7a75bfa0504043f6022694f59ae8:b7ccd5d0255b633cf5d15fbad047e2a1,track=2]../../content/sintel-720x306-24f-48g-730-1200k-5.1-256k.mp4"

Results:

  • The playready pssh box and the playready object are version 4.3 and contains both kids - good
  • The default_KID inside the manifest is different for audio and video tracks - good
  • The pssh inside the init fragment has playready pssh that is version 4.3 but contains single kid - not good
  • The Widevine pssh is missing from both the manifest and the init fragment - not good

Test 5:

  • use mp4encrypt to encrypt the content
    -- use one mp4 that is only audio
    -- use one mp4 that is only video
    -- use different keys

  • use mp4dash to create DASH
    -- tell bento4 to specifically generate pr header 4.3
    -- tell bento4 to merge keys

Command:

#!/bin/bash

../../bento4-linux/bin/mp4encrypt \
  --method MPEG-CENC \
  --key 1:c8cc8d5156c8188053f3f2a3139d4156:random --property 1:KID:9324cf3e1a1751efc2d4877c1528319a \
  ../../content/sintel-480x204-24f-48g-370-600k-5.1-256k-AUDIO-ONLY-FRAG.mp4 ./out/sintel-480x204-24f-48g-370-600k-5.1-256k-AUDIO-ONLY-FRAG-ENC.mp4

../../bento4-linux/bin/mp4encrypt \
  --method MPEG-CENC \
  --key 1:b7ccd5d0255b633cf5d15fbad047e2a1:random --property 1:KID:ac9c7a75bfa0504043f6022694f59ae8 \
  ../../content/sintel-480x204-24f-48g-370-600k-5.1-256k-VIDEO-ONLY-FRAG.mp4 ./out/sintel-480x204-24f-48g-370-600k-5.1-256k-VIDEO-ONLY-FRAG-ENC.mp4

../../bento4-linux/bin/mp4dash \
  --debug \
  -f \
  --widevine \
  --playready \
  --playready-version 4.3 \
  --merge-keys \
  --output-dir=./out-dash \
  --mpd-name=manifest.mpd \
  ./out/sintel-480x204-24f-48g-370-600k-5.1-256k-AUDIO-ONLY-FRAG-ENC.mp4 \
  ./out/sintel-480x204-24f-48g-370-600k-5.1-256k-VIDEO-ONLY-FRAG-ENC.mp4

Results:

  • The playready pssh box and the playready object are version 4.3 and contains both kids - good
  • The default_KID inside the manifest is different for audio and video tracks - good
  • The playready pssh is missing from the init fragment - not good
  • The Widevine pssh is missing from both the manifest and the init fragment - not good

Summary:

So, it looks like when using the mp4dash to package the content you must use mp4 files that have separate audio and video to not to confuse bento4 when creating the manifest. But, seems that it has issues generating the Widevine PSSH on its own and, for some reason, the PlayReady PSSH inside the init fragment contains only a single KID whereas the PSSH inside the Manifest and the PRO inside the manifest, both contain two KIDs.

When using mp4encrypt and then doing the packaging, we get the same result as if we would only use mp4dash with +key and files with audio/video only.

Questions are:

  • Is there a way to tell bento to generate valid PlayReady PSSH for the init fragment that would contain all KIDs as it does for the manifest?
  • Is there a way to tell bento to generate Widevine PSSH for the manifest and the init fragment that would contain all KIDs, or is it only possible if we pass our own pssh header for Widevine?

Thank you

@barbibulle
Copy link
Contributor

Hi.
Thanks for the detailed write up. Sorry for taking so long to follow up.
A few things to point out that may clarify some points:

  • Since you want per-track encryption, you absolutely need to ensure that each input passed to mp4dash selects only one track (by default, an input file passed as an argument will select all tracks found in the file). As you've seen in your different experiments, you can do that by either 1/ passing files that only have one track (example 5), or 2/ using an input filter prefix (like [track=1] for example).
  • For Widevine, if you don't use the --widevine-header command line option, no PSSH will be generated (because the tool can't decide for you what parameters should go in the PSSH, it needs to be passed in, as it includes some information that would be provided to you by your DRM provider/system)
  • For PlayReady, you can get a generic PSSH generated by the tool, but it is also likely you'll need to pass in the playready header information with --playready-header, for parameters like LA_URL, LUI_URL and DS_ID.
  • the --merge-keys is, as you found out, the way to tell the tool to combine all keys into a single set, rather than having different key lists for different tracks. However, this option currently only affects the keys information included in the DASH manifest (<ContentProtection> elements), not the PSSH that's included in the init segments. The init segments still only contain the information about the track to which they refer, which would be just one track per init segment here.

If it is a requirement that each init segment's PSSH data for Widevine and PlayReady include all KIDs, this is definitely something that can be added to the tool. Let me know if that's the case, I can make the modification.

@qchroman
Copy link
Author

qchroman commented Jun 5, 2024

Hello @barbibulle,

Thank you for the response. Indeed having all the KeyIDs inside the PSSH box in the init segment and the manifest is the requirement if one wants to utilize the multiple key DRM license. In this case, the DRM license server may issue a single license with multiple Content Keys inside.

Do I understand correctly that at this stage, the only approach is for us to generate the valid PSSH for both PlayReady and Widevine and

  1. pass it to the tool
  2. use the [track=1] for the per-track encryption

to get the asset in which each track is encrypted using its own keys and has correct PSSH boxes inside the manifest and inside the init fragments?

@qchroman
Copy link
Author

Hello @barbibulle,

Do you happen to have a roadmap that you could share for the product?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants