axiomatic-systems / Bento4

Full-featured MP4 format, MPEG DASH, HLS, CMAF SDK and tools
http://www.bento4.com
2.03k stars 483 forks source link

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

Open qchroman opened 6 months ago

qchroman commented 6 months ago

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 commented 6 months ago

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 commented 6 months ago

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:

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:

Test 2:

../../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 commented 5 months ago

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:

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 commented 5 months ago

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 commented 5 months ago

Hello @barbibulle,

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

riba101 commented 1 month ago

Hi @barbibulle,

I also have a related question for this topic. Is it possible to set seperate --widevine-header for the pssh boxes (for video and audio tracks), and can. I do the same with --fairplay-key-uri to get the values in the manifest? or will setting [+key=xxxx:xxxx] overwrite those values?