Skip to content

Commit

Permalink
feat(HLS): Add support for EXT-X-SESSION-KEY tag
Browse files Browse the repository at this point in the history
  • Loading branch information
avelad committed Nov 6, 2022
1 parent 59d4360 commit 21a877a
Show file tree
Hide file tree
Showing 2 changed files with 354 additions and 4 deletions.
66 changes: 62 additions & 4 deletions lib/hls/hls_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,9 @@ shaka.hls.HlsParser = class {
/** @type {!Array.<!shaka.hls.Tag>} */
const imageTags = Utils.filterTagsByName(
playlist.tags, 'EXT-X-IMAGE-STREAM-INF');
/** @type {!Array.<!shaka.hls.Tag>} */
const sessionKeyTags = Utils.filterTagsByName(
playlist.tags, 'EXT-X-SESSION-KEY');

this.parseCodecs_(variantTags);

Expand Down Expand Up @@ -691,7 +694,7 @@ shaka.hls.HlsParser = class {
// start time from audio/video streams and reuse for text streams.
this.createStreamInfosFromMediaTags_(mediaTags);
this.parseClosedCaptions_(mediaTags);
variants = this.createVariantsForTags_(variantTags);
variants = this.createVariantsForTags_(variantTags, sessionKeyTags);
textStreams = this.parseTexts_(mediaTags);
imageStreams = await this.parseImages_(imageTags);
}
Expand Down Expand Up @@ -964,10 +967,12 @@ shaka.hls.HlsParser = class {

/**
* @param {!Array.<!shaka.hls.Tag>} tags Variant tags from the playlist.
* @param {!Array.<!shaka.hls.Tag>} sessionKeyTags EXT-X-SESSION-KEY tags
* from the playlist.
* @return {!Array.<!shaka.extern.Variant>}
* @private
*/
createVariantsForTags_(tags) {
createVariantsForTags_(tags, sessionKeyTags) {
// Create variants for each variant tag.
const allVariants = tags.map((tag) => {
const frameRate = tag.getAttributeValue('FRAME-RATE');
Expand All @@ -985,14 +990,56 @@ shaka.hls.HlsParser = class {
goog.asserts.assert(streamInfos.audio.length ||
streamInfos.video.length, 'We should have created a stream!');

const drmInfos = [];
const keyIds = new Set();

if (sessionKeyTags.length > 0) {
const characteristics = tag.getAttributeValue('CHARACTERISTICS');
for (const drmTag of sessionKeyTags) {
const drmCharacteristics =
drmTag.getAttributeValue('CHARACTERISTICS');
if ((characteristics && !drmCharacteristics) ||
(!characteristics && drmCharacteristics) ||
(drmCharacteristics && characteristics &&
!characteristics.includes(drmCharacteristics))) {
continue;
}
const method = drmTag.getRequiredAttrValue('METHOD');
if (method != 'NONE' && method != 'AES-128') {
// According to the HLS spec, KEYFORMAT is optional and implicitly
// defaults to "identity".
// https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis-11#section-4.4.4.4
const keyFormat =
drmTag.getAttributeValue('KEYFORMAT') || 'identity';
const drmParser =
shaka.hls.HlsParser.KEYFORMATS_TO_DRM_PARSERS_[keyFormat];

const drmInfo = drmParser ?
drmParser(drmTag, /* mimeType= */ '') : null;
if (drmInfo) {
if (drmInfo.keyIds) {
for (const keyId of drmInfo.keyIds) {
keyIds.add(keyId);
}
}
drmInfos.push(drmInfo);
} else {
shaka.log.warning('Unsupported HLS KEYFORMAT', keyFormat);
}
}
}
}

return this.createVariants_(
streamInfos.audio,
streamInfos.video,
bandwidth,
width,
height,
frameRate,
videoRange);
videoRange,
drmInfos,
keyIds);
});
let variants = allVariants.reduce(shaka.util.Functional.collapseArrays, []);
// Filter out null variants.
Expand Down Expand Up @@ -1234,11 +1281,14 @@ shaka.hls.HlsParser = class {
* @param {?string} height
* @param {?string} frameRate
* @param {?string} videoRange
* @param {!Array.<shaka.extern.DrmInfo>} drmInfos
* @param {!Set.<string>} keyIds
* @return {!Array.<!shaka.extern.Variant>}
* @private
*/
createVariants_(
audioInfos, videoInfos, bandwidth, width, height, frameRate, videoRange) {
audioInfos, videoInfos, bandwidth, width, height, frameRate, videoRange,
drmInfos, keyIds) {
const ContentType = shaka.util.ManifestParserUtils.ContentType;
const DrmEngine = shaka.media.DrmEngine;

Expand All @@ -1264,7 +1314,15 @@ shaka.hls.HlsParser = class {
for (const audioInfo of audioInfos) {
for (const videoInfo of videoInfos) {
const audioStream = audioInfo ? audioInfo.stream : null;
if (audioStream) {
audioStream.drmInfos = drmInfos;
audioStream.keyIds = keyIds;
}
const videoStream = videoInfo ? videoInfo.stream : null;
if (videoStream) {
videoStream.drmInfos = drmInfos;
videoStream.keyIds = keyIds;
}
const audioDrmInfos = audioInfo ? audioInfo.stream.drmInfos : null;
const videoDrmInfos = videoInfo ? videoInfo.stream.drmInfos : null;
const videoStreamUri =
Expand Down
Loading

0 comments on commit 21a877a

Please sign in to comment.