Skip to content

Commit

Permalink
feat(dash): [ClearKey] Construct pssh box based on ContentProtection …
Browse files Browse the repository at this point in the history
…content in the mpd.
  • Loading branch information
sr1990 committed Apr 8, 2022
1 parent 57c7324 commit 4b66e2c
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 3 deletions.
53 changes: 50 additions & 3 deletions lib/dash/content_protection.js
Expand Up @@ -68,7 +68,7 @@ shaka.dash.ContentProtection = class {

if (parsedNonCenc.length) {
drmInfos = ContentProtection.convertElements_(
defaultInit, parsedNonCenc, keySystemsByURI);
defaultInit, parsedNonCenc, keySystemsByURI, keyIds);

// If there are no drmInfos after parsing, then add a dummy entry.
// This may be removed in parseKeyIds.
Expand Down Expand Up @@ -366,16 +366,48 @@ shaka.dash.ContentProtection = class {
];
}

/**
* Creates ClearKey initData from Default_KID value.
* @param {shaka.dash.ContentProtection.Element} element
* @param {!Set.<string>} keyIds
* @return {?Array.<shaka.extern.InitDataOverride>}
* @private
*/
static getInitDataClearKey_(element, keyIds) {
if (keyIds.size == 0) {
return null;
}

const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
const [first] = keyIds;
const data = Uint8ArrayUtils.fromHex(first);

const systemId = new Uint8Array([
0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02,
0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b,
]);

const pssh = shaka.util.Pssh.createPsshClearKey(data, systemId);
return [
{
initData: pssh,
initDataType: 'cenc',
keyId: element.keyId,
},
];
}

/**
* Creates DrmInfo objects from the given element.
*
* @param {Array.<shaka.extern.InitDataOverride>} defaultInit
* @param {!Array.<shaka.dash.ContentProtection.Element>} elements
* @param {!Object.<string, string>} keySystemsByURI
* @param {!Set.<string>} keyIds
* @return {!Array.<shaka.extern.DrmInfo>}
* @private
*/
static convertElements_(defaultInit, elements, keySystemsByURI) {
static convertElements_(defaultInit, elements, keySystemsByURI, keyIds) {
const ContentProtection = shaka.dash.ContentProtection;
const ManifestParserUtils = shaka.util.ManifestParserUtils;
const licenseUrlParsers = ContentProtection.licenseUrlParsers_;
Expand All @@ -391,7 +423,14 @@ shaka.dash.ContentProtection = class {
'Init data must be null or non-empty.');

const proInitData = ContentProtection.getInitDataFromPro_(element);
const initData = element.init || defaultInit || proInitData;
let clearKeyInitData = null;
if (element.schemeUri ===
shaka.dash.ContentProtection.ClearKeySchemeUri_) {
clearKeyInitData =
ContentProtection.getInitDataClearKey_(element, keyIds);
}
const initData = element.init || defaultInit || proInitData ||
clearKeyInitData;
const info = ManifestParserUtils.createDrmInfo(keySystem, initData);
const licenseParser = licenseUrlParsers.get(keySystem);
if (licenseParser) {
Expand Down Expand Up @@ -607,3 +646,11 @@ shaka.dash.ContentProtection.CencNamespaceUri_ = 'urn:mpeg:cenc:2013';
*/
shaka.dash.ContentProtection.ClearKeyNamespaceUri_ =
'http://dashif.org/guidelines/clearKey';


/**
* @const {string}
* @private
*/
shaka.dash.ContentProtection.ClearKeySchemeUri_ =
'urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e';
43 changes: 43 additions & 0 deletions lib/util/pssh.js
Expand Up @@ -124,6 +124,49 @@ shaka.util.Pssh = class {
return psshBox;
}

/**
* Creates a ClearKey cenc pssh blob from the given system ID and data.
* Data will contain one key id.
* Based on https://www.w3.org/TR/eme-initdata-cenc/
* @param {!Uint8Array} data
* @param {!Uint8Array} systemId
* @return {!Uint8Array}
*/
static createPsshClearKey(data, systemId) {
goog.asserts.assert(systemId.byteLength == 16, 'Invalid system ID length');
const dataLength = data.length;
const psshSize = 0x4 + // pssh size (4 bytes)
0x4 + // 'pssh' (4 bytes)
0x4 + // version (1 byte) + flags (3 bytes)
systemId.length + // system id (16 bytes)
0x4 + // KID count (4 bytes)
dataLength + // KID value (16 bytes)
0x4; // size of data (4 bytes)

/** @type {!Uint8Array} */
const psshBox = new Uint8Array(psshSize);
/** @type {!DataView} */
const psshData = shaka.util.BufferUtils.toDataView(psshBox);

let byteCursor = 0;
psshData.setUint32(byteCursor, psshSize);
byteCursor += 0x4;
psshData.setUint32(byteCursor, 0x70737368); // 'pssh'
byteCursor += 0x4;
psshData.setUint32(byteCursor, 0x01000000); // version = 1
byteCursor += 0x4;
psshBox.set(systemId, byteCursor);
byteCursor += systemId.length;
psshData.setUint32(byteCursor, 0x00000001); // KID_count
byteCursor += 0x4;
psshBox.set(data, byteCursor); // add kid
byteCursor += dataLength;
psshData.setUint32(byteCursor, 0x00000000);
byteCursor += 0x4;

goog.asserts.assert(byteCursor === psshSize, 'PSSH invalid length.');
return psshBox;
}

/**
* Normalise the initData array. This is to apply browser specific
Expand Down

0 comments on commit 4b66e2c

Please sign in to comment.