-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Feature: add EME ClearKey support #2934
base: master
Are you sure you want to change the base?
Conversation
Hi @itsjamie , can you (or anyone) help me review the code? Don't know why I cannot add a reviewer for this PR. I generated a |
Hello @calmbryan, if you could upload the test media somewhere, or the command you used to generate it, that would help testing. I understand that you're removing the transmux of SAMPLE-AES because you want to push users to push the MSE data through hls.js without it having to add code to decrypt the content. Have you looked to see what happens through transmuxUnencrypted on the mp4-demuxer to see if it is able to parse the boxes that are unencrypted? There was an earlier ticket around adding support for SAMPLE-AES support for fMP4 and ClearKey came up as a option then. It was closed after the reporter stated it wasn't necessary anymore. #1491 I've got some concerns with saying we support SAMPLE-AES encrypted content full-stop (removing the separate code path) if it requires setting up a ClearKey session that a user may not have set up. For example, if we were to use ClearKey for the purpose of supporting SAMPLE-AES, we should go about adding detection for a EXT-X-KEY within the m3u8-parser and the fragment encrypted property, and setup the ClearKey EME session for the user using the provided information in the HLS playlist. If you want to just add support for the ClearKey "CDM" to test an EME implementation, I wouldn't include your changes to the SAMPLE-AES transmuxing in this PR. |
Thanks @itsjamie ! Here is an sample mp4 video. This video will be parsed and encrypted in
Regarding the transmux of mp4, if we want to use SAMPLE-AES with ClearKey, the check should pass. Therefore, I add the check of For the next step, the check of URI and Key format can be added to m3u8-parser. I also find some To-do/issues regarding manifest, and it can be another PR. I went through #1491 when I began to explore SMAPLE-AES. According to @erankor : "there is no support for a 10% encryption ratio as in cbcs", that may be one of the reasons to close the issue. I don't think so in 2020. All CDMs begin to support |
993cf61
to
02c7fdd
Compare
Want to check the reason of failing of
|
videoCodecs: string[] | ||
): MediaKeySystemConfiguration[] { /* jshint ignore:line */ | ||
const baseConfig: MediaKeySystemConfiguration = { | ||
initDataTypes: ['keyids', 'mp4'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In some browsers; "cenc" is the init data type that will be selected when a org.w3.clearkey
keysystem is requested.
Additionally, encryptionScheme: 'cbcs'
can be added to further clarify the request
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
initDataTypes
for all keysystems can be found in utils/mediakeys-helper.ts:
https://github.com/video-dev/hls.js/blob/v1.3.0-beta.2/src/utils/mediakeys-helper.ts#L125-L126
keyarray.push( | ||
{ | ||
kty: 'oct', | ||
alg: 'A128KW', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The alg
property here can be removed.
|
||
var start = 0; | ||
var end = encodedBase64.length; | ||
while (end > start && encodedBase64[end - 1] === '=') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to also handle converting +
-> -
. and /
-> _
.
I had come up with these helpers when I was doing my validation.
// Helper function to do the Base64 UrlDecoding as described in the ClearKey spec
function base64urldecode(str) {
return window.atob(str.replace(/-/g, "+").replace(/_/g, "/"));
}
// Helper function to do the Base64 UrlEncoding as described in the ClearKey spec
function base64urlencode(str) {
return window.btoa(str).split('=')[0].replace(/\+/g, "-").replace(/\//g, "_")
}
@@ -589,8 +728,11 @@ class EMEController implements ComponentAPI { | |||
const videoCodecs = data.levels.map((level) => level.videoCodec).filter( | |||
(videoCodec: string | undefined): videoCodec is string => !!videoCodec | |||
); | |||
|
|||
this._attemptKeySystemAccess(KeySystems.WIDEVINE, audioCodecs, videoCodecs); | |||
if (this._clearkeyPair || this._clearkeyServerUrl) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We definitely don't want to always prefer setting up a ClearKey session over any real DRM protection if we get an encrypted
event from the browser.
I think this is potentially why we want to hook the HLS manifest parsing and preemptively setup a ClearKey MediaKeySession when we detect SAMPLE-AES based content. We can request from the user if they want to decrypt using ClearKey. And thats when we are provided with the ClearKey information the user thinks we will need to do playback.
@@ -501,6 +629,10 @@ class EMEController implements ComponentAPI { | |||
case KeySystems.WIDEVINE: | |||
// For Widevine CDMs, the challenge is the keyMessage. | |||
return keyMessage; | |||
case KeySystems.CLEARKEY: | |||
// For CLEARKEY, the challenge is the keyMessage. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a PSSH box. If we needed to for whatever reason provide the end-user with the contents of the key message, we could parse like this.
// precompute hex mapping from Uint8
const byteToHex = [];
for (let n = 0; n <= 0xff; ++n) {
const hexOctet = n.toString(16).padStart(2, "0");
byteToHex.push(hexOctet);
}
function hexFromAb(arrayBuffer) {
const buff = new Uint8Array(arrayBuffer);
const hexOctets = new Array(buff.length);
for (let i = 0; i < buff.length; ++i) {
hexOctets[i] = byteToHex[buff[i]];
}
return hexOctets.join("");
}
function parsePssh(buffer) {
const view = new DataView(buffer)
const boxSize = view.getUint32(0)
if (buffer.byteLength !== boxSize && boxSize > 44) {
console.assert('yikes not right')
}
const type = view.getUint32(4)
if (type != 1886614376) { // pssh
console.assert('yikes not right')
}
const fbHeader = view.getUint32(8)
const version = fbHeader >>> 24
const flags = fbHeader & 0x00FFFFFF;
if (version == 1) {
const systemId = hexFromAb(buffer.slice(12, 28))
const kidCount = view.getUint32(28)
const keyIds = []
for (let i = 0; i < kidCount; i++) {
keyIds.push(hexFromAb(buffer.slice(32 + (i * 16), 48 + (i * 16))))
}
return {
systemId,
keyIds
}
} else {
console.assert('unknown version')
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mp4pssh
parsing has been added to utils/mp4-tools.ts:
https://github.com/video-dev/hls.js/blob/v1.3.0-beta.2/src/utils/mp4-tools.ts#L1108
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to include the license generation/key pair config, and transmux change on top of #4930. Since this PR has been open for some time, I can merge this changes into a working branch and rebase from there.
@botengyao let me know if that sounds good to you or if you'd prefer to rebase after #4930 is merged.
clearkeyServerUrl
should not be needed as we're adding config.drmSystems[key-system]
blocks for all license and certificate URLs. I am thinking that is also where config.drmSystems['org.w3.clearkey'].keyPairs
can go (we should support multiple key-pairs no?).
Hi @robwalch, sorry, it is long time and I am not actively working on this. Feel free to reassign if someone wants to take over. Re-branching to the latest works for me with the best convenience. |
Thank you @botengyao. Apologies for not finding a path to accepting these contributions earlier. |
What is actual status of this feature? I woudl like to test it. Very nice feature. |
This PR will...
This PR will add the check of
org.w3.clearkey
and define the usage of the Clear Key.Adding ClearKey support will allow users to use SAMPLE-AES in HLS (cbcs pattern)
the config will add :
Users can specify the KeyID-Key pair in their configuration.
hls.js
will synchronously generate the license on the client following the spec. The usage is like:Users can also specify a ClearKey server URL through clearkeyServerUrl
Why is this Pull Request needed?
We currently only support Widevine, which requires us to establish a license server. There isn't a clear path to use Clear Key with hls.js according to #2901 . From the spec, all browsers supporting EME must implement Clear Key. That allows us to play the encrypted video by providing the Key.
The
org.w3.clearkey
Key System uses plain-text clear key(s) to decrypt the source. It is also handy for testing EME implementations, and applications using EME, without the need to request a content key from a complicated license server.Are there any points in the code the reviewer needs to double check?
Resolves issues:
#2901
Checklist