Skip to content

Commit

Permalink
chore: Partial cherry-pick and backport of #5656
Browse files Browse the repository at this point in the history
This is parts of #5656 cherry-picked and backported to support the cherry-pick of #5677, which fixes a bug in HLS.

Backported to v4.3.x
  • Loading branch information
joeyparrish committed Oct 4, 2023
1 parent 193abe4 commit a7d2f9b
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 16 deletions.
5 changes: 5 additions & 0 deletions demo/common/asset.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,11 @@ const ShakaDemoAssetInfo = class {
return this.drm.length == 1 && this.drm[0] == shakaAssets.KeySystem.CLEAR;
}

/** @return {boolean} */
isAes128() {
return this.drm.length == 1 && this.drm[0] == shakaAssets.KeySystem.AES128;
}

/**
* @param {string} mediaPlaylistFullMimeType
* @return {!ShakaDemoAssetInfo}
Expand Down
15 changes: 15 additions & 0 deletions demo/common/assets.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ shakaAssets.KeySystem = {
FAIRPLAY: shakaDemo.MessageIds.FAIRPLAY,
PLAYREADY: shakaDemo.MessageIds.PLAYREADY,
WIDEVINE: shakaDemo.MessageIds.WIDEVINE,
AES128: shakaDemo.MessageIds.AES128,
CLEAR: shakaDemo.MessageIds.CLEAR,
};

Expand Down Expand Up @@ -88,6 +89,7 @@ shakaAssets.identifierForKeySystem = (keySystem) => {
case KeySystem.FAIRPLAY: return 'com.apple.fps';
case KeySystem.PLAYREADY: return 'com.microsoft.playready';
case KeySystem.WIDEVINE: return 'com.widevine.alpha';
case KeySystem.AES128: return 'aes128';
default: return 'no drm protection';
}
};
Expand Down Expand Up @@ -355,6 +357,7 @@ shakaAssets.testAssets = [
/* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/sintel.png',
/* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/sintel-ts-aes-key-rotation/master.m3u8',
/* source= */ shakaAssets.Source.SHAKA)
.addKeySystem(shakaAssets.KeySystem.AES128)
.addFeature(shakaAssets.Feature.HLS)
.addFeature(shakaAssets.Feature.MP2TS)
.addFeature(shakaAssets.Feature.OFFLINE),
Expand All @@ -363,6 +366,7 @@ shakaAssets.testAssets = [
/* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/sintel.png',
/* manifestUri= */ 'https://storage.googleapis.com/shaka-demo-assets/sintel-fmp4-aes/master.m3u8',
/* source= */ shakaAssets.Source.SHAKA)
.addKeySystem(shakaAssets.KeySystem.AES128)
.addFeature(shakaAssets.Feature.HLS)
.addFeature(shakaAssets.Feature.MP4)
.addFeature(shakaAssets.Feature.OFFLINE),
Expand Down Expand Up @@ -931,6 +935,7 @@ shakaAssets.testAssets = [
/* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/art_of_motion.png',
/* manifestUri= */ 'https://bitmovin-a.akamaihd.net/content/art-of-motion_drm/m3u8s/11331.m3u8',
/* source= */ shakaAssets.Source.BITCODIN)
.addKeySystem(shakaAssets.KeySystem.AES128)
.addFeature(shakaAssets.Feature.HIGH_DEFINITION)
.addFeature(shakaAssets.Feature.HLS)
.addFeature(shakaAssets.Feature.MP2TS)
Expand Down Expand Up @@ -1060,6 +1065,16 @@ shakaAssets.testAssets = [
kind: 'subtitle',
mime: 'text/vtt',
}),
new ShakaDemoAssetInfo(
/* name= */ 'Sintel (DASH, AES-128)',
/* iconUri= */ 'https://storage.googleapis.com/shaka-asset-icons/sintel.png',
/* manifestUri= */ 'https://amssamples.streaming.mediaservices.windows.net/49b57c87-f5f3-48b3-ba22-c55cfdffa9cb/Sintel.ism/manifest(format=mpd-time-csf)',
/* source= */ shakaAssets.Source.AZURE_MEDIA_SERVICES)
.addKeySystem(shakaAssets.KeySystem.AES128)
.addFeature(shakaAssets.Feature.DASH)
.addFeature(shakaAssets.Feature.MP4)
.addFeature(shakaAssets.Feature.HIGH_DEFINITION)
.addFeature(shakaAssets.Feature.OFFLINE),
// End Azure Media Services assets }}}

// GPAC assets {{{
Expand Down
1 change: 1 addition & 0 deletions demo/common/message_ids.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ shakaDemo.MessageIds = {
WEBM: 'DEMO_WEBM',
XLINK: 'DEMO_XLINK',
/* Key systems. */
AES128: 'DEMO_AES128',
CLEAR: 'DEMO_CLEAR',
CLEAR_KEY: 'DEMO_CLEAR_KEY',
FAIRPLAY: 'DEMO_FAIRPLAY',
Expand Down
1 change: 1 addition & 0 deletions demo/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"DEMO_AD_SEARCH": "Filters for assets that have advertisements.",
"DEMO_AD_TAG_URL": "Ad Tag URL",
"DEMO_ADS_TAB": "Ads",
"DEMO_AES128": "AES-128 protection",
"DEMO_ALL_CONTENT": "ALL CONTENT",
"DEMO_ALWAYS_STREAM_TEXT": "Always Stream Text",
"DEMO_ALWAYS_STREAM_TEXT_WARNING": "Text must always be streamed while native controls are enabled, for captions to work.",
Expand Down
4 changes: 4 additions & 0 deletions demo/locales/source.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
"description": "The label on a field that allows users to provide a Ad Tag URL for a custom asset.",
"message": "Ad Tag URL"
},
"DEMO_AES128": {
"description": "Text that describes an asset that is not protected with any Digital Rights Management system but it is protected with AES-128.",
"message": "[JARGON:AES-128] protection"
},
"DEMO_ALL_CONTENT": {
"description": "A link in the header, that switches to a page for browsing or searching through the entire content library.",
"message": "ALL CONTENT"
Expand Down
2 changes: 1 addition & 1 deletion demo/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ shakaDemo.Main = class {
return shakaDemo.MessageIds.UNSUPPORTED_NO_DOWNLOAD;
}

if (!asset.isClear()) {
if (!asset.isClear() && !asset.isAes128()) {
const hasSupportedDRM = asset.drm.some((drm) => {
return this.support_.drm[shakaAssets.identifierForKeySystem(drm)];
});
Expand Down
16 changes: 11 additions & 5 deletions lib/media/segment_reference.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,14 @@ shaka.media.InitSegmentReference = class {
* @param {?number} endByte The offset from the start of the resource
* to the end of the segment, inclusive. A value of null indicates that the
* segment extends to the end of the resource.
* @param {null|shaka.extern.MediaQualityInfo=} mediaQuality Information about
* the quality of the media associated with this init segment.
* @param {number=} timescale
* @param {(null|shaka.extern.MediaQualityInfo)=} mediaQuality Information
* about the quality of the media associated with this init segment.
* @param {(null|number)=} timescale
* @param {?shaka.extern.HlsAes128Key=} aes128Key
* The segment's AES-128-CBC full segment encryption key and iv.
*/
constructor(uris, startByte, endByte, mediaQuality = null, timescale) {
constructor(uris, startByte, endByte, mediaQuality = null, timescale = null,
aes128Key = null) {
/** @type {function():!Array.<string>} */
this.getUris = uris;

Expand All @@ -44,8 +47,11 @@ shaka.media.InitSegmentReference = class {
/** @const {shaka.extern.MediaQualityInfo|null} */
this.mediaQuality = mediaQuality;

/** @type {number|undefined} */
/** @type {number|null} */
this.timescale = timescale;

/** @type {?shaka.extern.HlsAes128Key} */
this.hlsAes128Key = aes128Key;
}

/**
Expand Down
22 changes: 12 additions & 10 deletions lib/media/streaming_engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -1357,16 +1357,11 @@ shaka.media.StreamingEngine = class {
'ReadableStream is not supported by the browser.');
}
const fetchSegment = this.fetch_(mediaState, reference);
let result = await fetchSegment;
const result = await fetchSegment;
this.destroyer_.ensureNotDestroyed();
if (this.fatalError_) {
return;
}
if (reference.hlsAes128Key) {
goog.asserts.assert(iter, 'mediaState.segmentIterator should exist');
result = await this.aes128Decrypt_(result, reference, iter);
}
this.destroyer_.ensureNotDestroyed();

// If the text stream gets switched between fetch_() and append_(), the
// new text parser is initialized, but the new init segment is not
Expand Down Expand Up @@ -1450,13 +1445,13 @@ shaka.media.StreamingEngine = class {

/**
* @param {!BufferSource} rawResult
* @param {!shaka.media.SegmentReference} reference
* @param {shaka.extern.HlsAes128Key} aes128Key
* @param {!shaka.media.SegmentIterator} iter
* @return {!Promise.<!BufferSource>} finalResult
* @private
*/
async aes128Decrypt_(rawResult, reference, iter) {
const key = reference.hlsAes128Key;
async aes128Decrypt_(rawResult, aes128Key, iter) {
const key = aes128Key;
if (!key.cryptoKey) {
goog.asserts.assert(key.fetchKey, 'If AES-128 cryptoKey was not ' +
'preloaded, fetchKey function should be provided');
Expand Down Expand Up @@ -2092,7 +2087,14 @@ shaka.media.StreamingEngine = class {
mediaState.operation = op;
const response = await op.promise;
mediaState.operation = null;
return response.data;

let result = response.data;
if (reference.hlsAes128Key) {
const iter = mediaState.segmentIterator;
goog.asserts.assert(iter, 'mediaState.segmentIterator should exist');
result = await this.aes128Decrypt_(result, reference.hlsAes128Key, iter);
}
return result;
}


Expand Down

0 comments on commit a7d2f9b

Please sign in to comment.