-
Notifications
You must be signed in to change notification settings - Fork 100
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
feat: parse key attributes for Widevine HLS #88
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
import Stream from './stream'; | ||
import LineStream from './line-stream'; | ||
import ParseStream from './parse-stream'; | ||
import decodeB64ToUint8Array from './utils/decode'; | ||
|
||
/** | ||
* A parser for M3U8 files. The current interpretation of the input is | ||
|
@@ -49,6 +50,9 @@ export default class Parser extends Stream { | |
'CLOSED-CAPTIONS': {}, | ||
'SUBTITLES': {} | ||
}; | ||
// This is the Widevine UUID from DASH IF IOP. The same exact string is | ||
// used in MPDs with Widevine encrypted streams. | ||
const widevineUuid = 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
// group segments into numbered timelines delineated by discontinuities | ||
let currentTimeline = 0; | ||
|
||
|
@@ -143,6 +147,55 @@ export default class Parser extends Stream { | |
}); | ||
return; | ||
} | ||
|
||
// check if the content is encrypted for Widevine | ||
// Widevine/HLS spec: https://storage.googleapis.com/wvdocs/Widevine_DRM_HLS.pdf | ||
if (entry.attributes.KEYFORMAT === widevineUuid) { | ||
const VALID_METHODS = ['SAMPLE-AES', 'SAMPLE-AES-CTR', 'SAMPLE-AES-CENC']; | ||
|
||
if (VALID_METHODS.indexOf(entry.attributes.METHOD) === -1) { | ||
this.trigger('warn', { | ||
message: 'invalid key method provided for Widevine' | ||
}); | ||
return; | ||
} | ||
|
||
if (entry.attributes.METHOD === 'SAMPLE-AES-CENC') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This case is fine just deprecated? Maybe we should group the ones that exit early? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just logging a warning should be fine. The spec didn't replace |
||
this.trigger('warn', { | ||
message: 'SAMPLE-AES-CENC is deprecated, please use SAMPLE-AES-CTR instead' | ||
}); | ||
} | ||
|
||
if (entry.attributes.URI.substring(0, 23) !== 'data:text/plain;base64,') { | ||
this.trigger('warn', { | ||
message: 'invalid key URI provided for Widevine' | ||
}); | ||
return; | ||
} | ||
|
||
if (!(entry.attributes.KEYID && entry.attributes.KEYID.substring(0, 2) === '0x')) { | ||
this.trigger('warn', { | ||
message: 'invalid key ID provided for Widevine' | ||
}); | ||
return; | ||
} | ||
|
||
// if Widevine key attributes are valid, store them as `contentProtection` | ||
// on the manifest to emulate Widevine tag structure in a DASH mpd | ||
this.manifest.contentProtection = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should we call this out specifically as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess the mpd parser calls it this as well? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You mean renaming |
||
'com.widevine.alpha': { | ||
attributes: { | ||
schemeIdUri: entry.attributes.KEYFORMAT, | ||
// remove '0x' from the key id string | ||
keyId: entry.attributes.KEYID.substring(2) | ||
}, | ||
// decode the base64-encoded PSSH box | ||
pssh: decodeB64ToUint8Array(entry.attributes.URI.split(',')[1]) | ||
} | ||
}; | ||
return; | ||
} | ||
|
||
if (!entry.attributes.METHOD) { | ||
this.trigger('warn', { | ||
message: 'defaulting key method to AES-128' | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import window from 'global/window'; | ||
|
||
export default function decodeB64ToUint8Array(b64Text) { | ||
const decodedString = window.atob(b64Text || ''); | ||
const array = new Uint8Array(decodedString.length); | ||
|
||
for (let i = 0; i < decodedString.length; i++) { | ||
array[i] = decodedString.charCodeAt(i); | ||
} | ||
return array; | ||
} |
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.
this is from the spec?
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.
Yeah, I had the same question. It's in the spec doc... 🤷♂
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.
Yep, and the same string is used for mpds (see mpd-parser)
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.
Might be useful to add a comment and link to the widevine hls extension spec