shaka-player 4.8.8 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/deps.js +5 -5
- package/dist/locales.js +33 -33
- package/dist/shaka-player.compiled.d.ts +39 -17
- package/dist/shaka-player.compiled.debug.d.ts +39 -17
- package/dist/shaka-player.compiled.debug.externs.js +32 -11
- package/dist/shaka-player.compiled.debug.js +574 -516
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +32 -11
- package/dist/shaka-player.compiled.js +1270 -1236
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +39 -17
- package/dist/shaka-player.ui.debug.d.ts +39 -17
- package/dist/shaka-player.ui.debug.externs.js +43 -22
- package/dist/shaka-player.ui.debug.js +601 -543
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +43 -22
- package/dist/shaka-player.ui.js +1483 -1448
- package/dist/shaka-player.ui.map +4 -4
- package/externs/shaka/manifest.js +11 -1
- package/externs/shaka/offline.js +3 -0
- package/externs/shaka/player.js +105 -12
- package/externs/tizen.js +1 -1
- package/lib/abr/simple_abr_manager.js +5 -0
- package/lib/ads/media_tailor_ad.js +11 -0
- package/lib/ads/media_tailor_ad_manager.js +37 -3
- package/lib/cea/cea608_data_channel.js +9 -0
- package/lib/cea/cea_decoder.js +6 -2
- package/lib/dash/dash_parser.js +655 -46
- package/lib/dash/mpd_utils.js +7 -8
- package/lib/dash/segment_template.js +65 -10
- package/lib/hls/hls_parser.js +92 -34
- package/lib/media/drm_engine.js +274 -40
- package/lib/media/manifest_filterer.js +10 -14
- package/lib/media/preload_manager.js +3 -10
- package/lib/media/segment_utils.js +14 -3
- package/lib/mss/mss_parser.js +2 -0
- package/lib/net/http_plugin_utils.js +2 -1
- package/lib/net/networking_engine.js +27 -0
- package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
- package/lib/offline/manifest_converter.js +2 -0
- package/lib/offline/storage.js +1 -0
- package/lib/player.js +221 -14
- package/lib/polyfill/media_capabilities.js +10 -35
- package/lib/util/config_utils.js +74 -6
- package/lib/util/error.js +7 -0
- package/lib/util/mp4_box_parsers.js +23 -2
- package/lib/util/periods.js +51 -28
- package/lib/util/platform.js +3 -1
- package/lib/util/player_configuration.js +20 -8
- package/lib/util/stream_utils.js +62 -30
- package/lib/util/tXml.js +74 -6
- package/package.json +2 -2
- package/support.html +1 -0
- package/ui/controls.js +4 -0
- package/ui/less/ad_controls.less +2 -1
- package/ui/resolution_selection.js +12 -3
package/lib/dash/mpd_utils.js
CHANGED
|
@@ -123,7 +123,7 @@ shaka.dash.MpdUtils = class {
|
|
|
123
123
|
* Expands a SegmentTimeline into an array-based timeline. The results are in
|
|
124
124
|
* seconds.
|
|
125
125
|
*
|
|
126
|
-
* @param {
|
|
126
|
+
* @param {Array<!shaka.extern.xml.Node>} timePoints
|
|
127
127
|
* @param {number} timescale
|
|
128
128
|
* @param {number} unscaledPresentationTimeOffset
|
|
129
129
|
* @param {number} periodDuration The Period's duration in seconds.
|
|
@@ -132,7 +132,7 @@ shaka.dash.MpdUtils = class {
|
|
|
132
132
|
* @return {!Array.<shaka.media.PresentationTimeline.TimeRange>}
|
|
133
133
|
*/
|
|
134
134
|
static createTimeline(
|
|
135
|
-
|
|
135
|
+
timePoints, timescale, unscaledPresentationTimeOffset,
|
|
136
136
|
periodDuration, startNumber) {
|
|
137
137
|
goog.asserts.assert(
|
|
138
138
|
timescale > 0 && timescale < Infinity,
|
|
@@ -143,8 +143,6 @@ shaka.dash.MpdUtils = class {
|
|
|
143
143
|
// Alias.
|
|
144
144
|
const TXml = shaka.util.TXml;
|
|
145
145
|
|
|
146
|
-
const timePoints = TXml.findChildren(segmentTimeline, 'S');
|
|
147
|
-
|
|
148
146
|
/** @type {!Array.<shaka.media.PresentationTimeline.TimeRange>} */
|
|
149
147
|
const timeline = [];
|
|
150
148
|
let lastEndTime = -unscaledPresentationTimeOffset;
|
|
@@ -296,13 +294,14 @@ shaka.dash.MpdUtils = class {
|
|
|
296
294
|
startNumber = 1;
|
|
297
295
|
}
|
|
298
296
|
|
|
299
|
-
const timelineNode =
|
|
300
|
-
MpdUtils.inheritChild(context, callback, 'SegmentTimeline');
|
|
301
297
|
/** @type {Array.<shaka.media.PresentationTimeline.TimeRange>} */
|
|
302
298
|
let timeline = null;
|
|
299
|
+
const timelineNode =
|
|
300
|
+
MpdUtils.inheritChild(context, callback, 'SegmentTimeline');
|
|
303
301
|
if (timelineNode) {
|
|
302
|
+
const timePoints = TXml.findChildren(timelineNode, 'S');
|
|
304
303
|
timeline = MpdUtils.createTimeline(
|
|
305
|
-
|
|
304
|
+
timePoints, timescale, unscaledPresentationTimeOffset,
|
|
306
305
|
context.periodInfo.duration || Infinity, startNumber);
|
|
307
306
|
}
|
|
308
307
|
|
|
@@ -329,7 +328,7 @@ shaka.dash.MpdUtils = class {
|
|
|
329
328
|
const Functional = shaka.util.Functional;
|
|
330
329
|
goog.asserts.assert(
|
|
331
330
|
callback(context.representation),
|
|
332
|
-
'There must be at least one element of the given type',
|
|
331
|
+
'There must be at least one element of the given type.',
|
|
333
332
|
);
|
|
334
333
|
|
|
335
334
|
return [
|
|
@@ -18,6 +18,7 @@ goog.require('shaka.util.IReleasable');
|
|
|
18
18
|
goog.require('shaka.util.ManifestParserUtils');
|
|
19
19
|
goog.require('shaka.util.ObjectUtils');
|
|
20
20
|
goog.require('shaka.util.StringUtils');
|
|
21
|
+
goog.require('shaka.util.TXml');
|
|
21
22
|
goog.requireType('shaka.dash.DashParser');
|
|
22
23
|
goog.requireType('shaka.media.PresentationTimeline');
|
|
23
24
|
|
|
@@ -39,18 +40,27 @@ shaka.dash.SegmentTemplate = class {
|
|
|
39
40
|
* @param {!Object.<string, number>} periodDurationMap
|
|
40
41
|
* @param {shaka.extern.aesKey|undefined} aesKey
|
|
41
42
|
* @param {?number} lastSegmentNumber
|
|
43
|
+
* @param {boolean} isPatchUpdate
|
|
42
44
|
* @return {shaka.dash.DashParser.StreamInfo}
|
|
43
45
|
*/
|
|
44
46
|
static createStreamInfo(
|
|
45
47
|
context, requestSegment, streamMap, isUpdate, segmentLimit,
|
|
46
|
-
periodDurationMap, aesKey, lastSegmentNumber) {
|
|
48
|
+
periodDurationMap, aesKey, lastSegmentNumber, isPatchUpdate) {
|
|
47
49
|
goog.asserts.assert(context.representation.segmentTemplate,
|
|
48
|
-
'Should only be called with SegmentTemplate'
|
|
50
|
+
'Should only be called with SegmentTemplate ' +
|
|
51
|
+
'or segment info defined');
|
|
52
|
+
const MpdUtils = shaka.dash.MpdUtils;
|
|
49
53
|
const SegmentTemplate = shaka.dash.SegmentTemplate;
|
|
50
54
|
const TimelineSegmentIndex = shaka.dash.TimelineSegmentIndex;
|
|
51
55
|
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
if (!isPatchUpdate && !context.representation.initialization) {
|
|
57
|
+
context.representation.initialization =
|
|
58
|
+
MpdUtils.inheritAttribute(
|
|
59
|
+
context, SegmentTemplate.fromInheritance_, 'initialization');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const initSegmentReference = context.representation.initialization ?
|
|
63
|
+
SegmentTemplate.createInitSegment_(context, aesKey) : null;
|
|
54
64
|
|
|
55
65
|
/** @type {shaka.dash.SegmentTemplate.SegmentTemplateInfo} */
|
|
56
66
|
const info = SegmentTemplate.parseSegmentTemplateInfo_(context);
|
|
@@ -178,6 +188,42 @@ shaka.dash.SegmentTemplate = class {
|
|
|
178
188
|
}
|
|
179
189
|
}
|
|
180
190
|
|
|
191
|
+
/**
|
|
192
|
+
* Ingests Patch MPD segments into timeline.
|
|
193
|
+
*
|
|
194
|
+
* @param {!shaka.dash.DashParser.Context} context
|
|
195
|
+
* @param {shaka.extern.xml.Node} patchNode
|
|
196
|
+
*/
|
|
197
|
+
static modifyTimepoints(context, patchNode) {
|
|
198
|
+
const MpdUtils = shaka.dash.MpdUtils;
|
|
199
|
+
const SegmentTemplate = shaka.dash.SegmentTemplate;
|
|
200
|
+
const TXml = shaka.util.TXml;
|
|
201
|
+
|
|
202
|
+
const timelineNode = MpdUtils.inheritChild(context,
|
|
203
|
+
SegmentTemplate.fromInheritance_, 'SegmentTimeline');
|
|
204
|
+
goog.asserts.assert(timelineNode, 'timeline node not found');
|
|
205
|
+
const timepoints = TXml.findChildren(timelineNode, 'S');
|
|
206
|
+
|
|
207
|
+
goog.asserts.assert(timepoints, 'timepoints should exist');
|
|
208
|
+
TXml.modifyNodes(timepoints, patchNode);
|
|
209
|
+
timelineNode.children = timepoints;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Removes all segments from timeline.
|
|
214
|
+
*
|
|
215
|
+
* @param {!shaka.dash.DashParser.Context} context
|
|
216
|
+
*/
|
|
217
|
+
static removeTimepoints(context) {
|
|
218
|
+
const MpdUtils = shaka.dash.MpdUtils;
|
|
219
|
+
const SegmentTemplate = shaka.dash.SegmentTemplate;
|
|
220
|
+
|
|
221
|
+
const timelineNode = MpdUtils.inheritChild(context,
|
|
222
|
+
SegmentTemplate.fromInheritance_, 'SegmentTimeline');
|
|
223
|
+
goog.asserts.assert(timelineNode, 'timeline node not found');
|
|
224
|
+
timelineNode.children = [];
|
|
225
|
+
}
|
|
226
|
+
|
|
181
227
|
/**
|
|
182
228
|
* @param {?shaka.dash.DashParser.InheritanceFrame} frame
|
|
183
229
|
* @return {?shaka.extern.xml.Node}
|
|
@@ -203,6 +249,7 @@ shaka.dash.SegmentTemplate = class {
|
|
|
203
249
|
|
|
204
250
|
const media = MpdUtils.inheritAttribute(
|
|
205
251
|
context, SegmentTemplate.fromInheritance_, 'media');
|
|
252
|
+
|
|
206
253
|
const index = MpdUtils.inheritAttribute(
|
|
207
254
|
context, SegmentTemplate.fromInheritance_, 'index');
|
|
208
255
|
|
|
@@ -552,8 +599,11 @@ shaka.dash.SegmentTemplate = class {
|
|
|
552
599
|
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
553
600
|
const SegmentTemplate = shaka.dash.SegmentTemplate;
|
|
554
601
|
|
|
555
|
-
let initialization =
|
|
556
|
-
|
|
602
|
+
let initialization = context.representation.initialization;
|
|
603
|
+
if (!initialization) {
|
|
604
|
+
initialization = MpdUtils.inheritAttribute(
|
|
605
|
+
context, SegmentTemplate.fromInheritance_, 'initialization');
|
|
606
|
+
}
|
|
557
607
|
if (!initialization) {
|
|
558
608
|
return null;
|
|
559
609
|
}
|
|
@@ -722,10 +772,15 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
722
772
|
this.templateInfo_.mediaTemplate = info.mediaTemplate;
|
|
723
773
|
|
|
724
774
|
// Append timeline
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
775
|
+
let newEntries;
|
|
776
|
+
if (currentTimeline.length) {
|
|
777
|
+
const lastCurrentEntry = currentTimeline[currentTimeline.length - 1];
|
|
778
|
+
newEntries = info.timeline.filter((entry) => {
|
|
779
|
+
return entry.start >= lastCurrentEntry.end;
|
|
780
|
+
});
|
|
781
|
+
} else {
|
|
782
|
+
newEntries = info.timeline.slice();
|
|
783
|
+
}
|
|
729
784
|
|
|
730
785
|
if (newEntries.length > 0) {
|
|
731
786
|
shaka.log.debug(`Appending ${newEntries.length} entries`);
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -244,6 +244,9 @@ shaka.hls.HlsParser = class {
|
|
|
244
244
|
|
|
245
245
|
/** @private {?shaka.util.ContentSteeringManager} */
|
|
246
246
|
this.contentSteeringManager_ = null;
|
|
247
|
+
|
|
248
|
+
/** @private {boolean} */
|
|
249
|
+
this.needsClosedCaptionsDetection_ = true;
|
|
247
250
|
}
|
|
248
251
|
|
|
249
252
|
|
|
@@ -759,10 +762,19 @@ shaka.hls.HlsParser = class {
|
|
|
759
762
|
|
|
760
763
|
// Parsing a media playlist results in a single-variant stream.
|
|
761
764
|
if (playlist.type == shaka.hls.PlaylistType.MEDIA) {
|
|
765
|
+
this.needsClosedCaptionsDetection_ = false;
|
|
766
|
+
|
|
767
|
+
/** @type {!Array.<!shaka.hls.Tag>} */
|
|
768
|
+
const variablesTags = shaka.hls.Utils.filterTagsByName(playlist.tags,
|
|
769
|
+
'EXT-X-DEFINE');
|
|
770
|
+
|
|
771
|
+
const mediaVariables =
|
|
772
|
+
this.parseMediaVariables_(variablesTags, this.masterPlaylistUri_);
|
|
773
|
+
|
|
762
774
|
// Get necessary info for this stream. These are things we would normally
|
|
763
775
|
// find from the master playlist (e.g. from values on EXT-X-MEDIA tags).
|
|
764
|
-
const basicInfo =
|
|
765
|
-
|
|
776
|
+
const basicInfo = await this.getMediaPlaylistBasicInfo_(
|
|
777
|
+
playlist, getUris, mediaVariables);
|
|
766
778
|
const type = basicInfo.type;
|
|
767
779
|
const mimeType = basicInfo.mimeType;
|
|
768
780
|
const codecs = basicInfo.codecs;
|
|
@@ -773,6 +785,7 @@ shaka.hls.HlsParser = class {
|
|
|
773
785
|
const sampleRate = basicInfo.sampleRate;
|
|
774
786
|
const closedCaptions = basicInfo.closedCaptions;
|
|
775
787
|
const videoRange = basicInfo.videoRange;
|
|
788
|
+
const colorGamut = basicInfo.colorGamut;
|
|
776
789
|
|
|
777
790
|
// Some values we cannot figure out, and aren't important enough to ask
|
|
778
791
|
// the user to provide through config values. A lot of these are only
|
|
@@ -786,14 +799,15 @@ shaka.hls.HlsParser = class {
|
|
|
786
799
|
|
|
787
800
|
// Make the stream info, with those values.
|
|
788
801
|
const streamInfo = await this.convertParsedPlaylistIntoStreamInfo_(
|
|
789
|
-
this.globalId_++, playlist, getUris, uri, codecs,
|
|
790
|
-
languageValue, primary, name, channelsCount, closedCaptions,
|
|
802
|
+
this.globalId_++, mediaVariables, playlist, getUris, uri, codecs,
|
|
803
|
+
type, languageValue, primary, name, channelsCount, closedCaptions,
|
|
791
804
|
characteristics, forced, sampleRate, spatialAudio, mimeType);
|
|
792
805
|
this.uriToStreamInfosMap_.set(uri, streamInfo);
|
|
793
806
|
|
|
794
807
|
if (type == 'video') {
|
|
795
808
|
this.addVideoAttributes_(streamInfo.stream, width, height,
|
|
796
|
-
/* frameRate= */ null, videoRange, /* videoLayout= */ null
|
|
809
|
+
/* frameRate= */ null, videoRange, /* videoLayout= */ null,
|
|
810
|
+
colorGamut);
|
|
797
811
|
}
|
|
798
812
|
|
|
799
813
|
// Wrap the stream from that stream info with a variant.
|
|
@@ -880,6 +894,7 @@ shaka.hls.HlsParser = class {
|
|
|
880
894
|
this.config_.hls.ignoreManifestTimestampsInSegmentsMode,
|
|
881
895
|
type: shaka.media.ManifestParser.HLS,
|
|
882
896
|
serviceDescription: null,
|
|
897
|
+
nextUrl: null,
|
|
883
898
|
};
|
|
884
899
|
|
|
885
900
|
// If there is no 'CODECS' attribute in the manifest and codec guessing is
|
|
@@ -918,10 +933,11 @@ shaka.hls.HlsParser = class {
|
|
|
918
933
|
/**
|
|
919
934
|
* @param {shaka.hls.Playlist} playlist
|
|
920
935
|
* @param {function():!Array.<string>} getUris
|
|
936
|
+
* @param {?Map.<string, string>=} variables
|
|
921
937
|
* @return {!Promise.<shaka.media.SegmentUtils.BasicInfo>}
|
|
922
938
|
* @private
|
|
923
939
|
*/
|
|
924
|
-
async getMediaPlaylistBasicInfo_(playlist, getUris) {
|
|
940
|
+
async getMediaPlaylistBasicInfo_(playlist, getUris, variables) {
|
|
925
941
|
const HlsParser = shaka.hls.HlsParser;
|
|
926
942
|
const defaultBasicInfo = shaka.media.SegmentUtils.getBasicInfoFromMimeType(
|
|
927
943
|
this.config_.hls.mediaPlaylistFullMimeType);
|
|
@@ -931,7 +947,8 @@ shaka.hls.HlsParser = class {
|
|
|
931
947
|
const firstSegment = playlist.segments[0];
|
|
932
948
|
const firstSegmentUris = shaka.hls.Utils.constructSegmentUris(
|
|
933
949
|
getUris(),
|
|
934
|
-
firstSegment.verbatimSegmentUri
|
|
950
|
+
firstSegment.verbatimSegmentUri,
|
|
951
|
+
variables);
|
|
935
952
|
const firstSegmentUri = firstSegmentUris[0];
|
|
936
953
|
const parsedUri = new goog.Uri(firstSegmentUri);
|
|
937
954
|
const extension = parsedUri.getPath().split('.').pop();
|
|
@@ -945,7 +962,7 @@ shaka.hls.HlsParser = class {
|
|
|
945
962
|
|
|
946
963
|
let initData = null;
|
|
947
964
|
const initSegmentRef = this.getInitSegmentReference_(
|
|
948
|
-
playlist, firstSegment.tags, getUris);
|
|
965
|
+
playlist, firstSegment.tags, getUris, variables);
|
|
949
966
|
this.mapTagToInitSegmentRefMap_.clear();
|
|
950
967
|
if (initSegmentRef) {
|
|
951
968
|
const initSegmentRequest = shaka.util.Networking.createSegmentRequest(
|
|
@@ -1388,7 +1405,19 @@ shaka.hls.HlsParser = class {
|
|
|
1388
1405
|
const keyFormat =
|
|
1389
1406
|
drmTag.getAttributeValue('KEYFORMAT') || 'identity';
|
|
1390
1407
|
let drmInfo = null;
|
|
1391
|
-
if (method == 'NONE'
|
|
1408
|
+
if (method == 'NONE') {
|
|
1409
|
+
continue;
|
|
1410
|
+
} else if (this.isAesMethod_(method)) {
|
|
1411
|
+
const keyUris = shaka.hls.Utils.constructSegmentUris(
|
|
1412
|
+
getUris(), drmTag.getRequiredAttrValue('URI'), variables);
|
|
1413
|
+
const keyMapKey = keyUris.sort().join('');
|
|
1414
|
+
if (!this.aesKeyMap_.has(keyMapKey)) {
|
|
1415
|
+
const requestType = shaka.net.NetworkingEngine.RequestType.KEY;
|
|
1416
|
+
const request = shaka.net.NetworkingEngine.makeRequest(
|
|
1417
|
+
keyUris, this.config_.retryParameters);
|
|
1418
|
+
const keyResponse = this.makeNetworkRequest_(request, requestType);
|
|
1419
|
+
this.aesKeyMap_.set(keyMapKey, keyResponse);
|
|
1420
|
+
}
|
|
1392
1421
|
continue;
|
|
1393
1422
|
} else if (keyFormat == 'identity') {
|
|
1394
1423
|
// eslint-disable-next-line no-await-in-loop
|
|
@@ -1755,10 +1784,12 @@ shaka.hls.HlsParser = class {
|
|
|
1755
1784
|
// value of the GROUP-ID attribute of an EXT-X-MEDIA tag elsewhere in the
|
|
1756
1785
|
// Playlist whose TYPE attribute is CLOSED-CAPTIONS.
|
|
1757
1786
|
if (type == ContentType.VIDEO) {
|
|
1758
|
-
if (closedCaptionsAttr
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1787
|
+
if (closedCaptionsAttr) {
|
|
1788
|
+
if (closedCaptionsAttr != 'NONE') {
|
|
1789
|
+
return this.groupIdToClosedCaptionsMap_.get(closedCaptionsAttr);
|
|
1790
|
+
}
|
|
1791
|
+
this.needsClosedCaptionsDetection_ = false;
|
|
1792
|
+
} else if (!closedCaptionsAttr && this.groupIdToClosedCaptionsMap_.size) {
|
|
1762
1793
|
for (const key of this.groupIdToClosedCaptionsMap_.keys()) {
|
|
1763
1794
|
return this.groupIdToClosedCaptionsMap_.get(key);
|
|
1764
1795
|
}
|
|
@@ -1817,7 +1848,8 @@ shaka.hls.HlsParser = class {
|
|
|
1817
1848
|
|
|
1818
1849
|
for (const info of videoInfos) {
|
|
1819
1850
|
this.addVideoAttributes_(
|
|
1820
|
-
info.stream, width, height, frameRate, videoRange, videoLayout
|
|
1851
|
+
info.stream, width, height, frameRate, videoRange, videoLayout,
|
|
1852
|
+
/** colorGamut= */ null);
|
|
1821
1853
|
}
|
|
1822
1854
|
|
|
1823
1855
|
// In case of audio-only or video-only content or the audio/video is
|
|
@@ -1907,6 +1939,7 @@ shaka.hls.HlsParser = class {
|
|
|
1907
1939
|
parseClosedCaptions_(mediaTags) {
|
|
1908
1940
|
const closedCaptionsTags =
|
|
1909
1941
|
shaka.hls.Utils.filterTagsByType(mediaTags, 'CLOSED-CAPTIONS');
|
|
1942
|
+
this.needsClosedCaptionsDetection_ = closedCaptionsTags.length == 0;
|
|
1910
1943
|
for (const tag of closedCaptionsTags) {
|
|
1911
1944
|
goog.asserts.assert(tag.name == 'EXT-X-MEDIA',
|
|
1912
1945
|
'Should only be called on media tags!');
|
|
@@ -2248,6 +2281,8 @@ shaka.hls.HlsParser = class {
|
|
|
2248
2281
|
|
|
2249
2282
|
/** @param {!AbortSignal} abortSignal */
|
|
2250
2283
|
const downloadSegmentIndex = async (abortSignal) => {
|
|
2284
|
+
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
2285
|
+
|
|
2251
2286
|
const uris = streamInfo.getUris();
|
|
2252
2287
|
// Download the actual manifest.
|
|
2253
2288
|
const response = await this.requestManifest_(
|
|
@@ -2267,24 +2302,47 @@ shaka.hls.HlsParser = class {
|
|
|
2267
2302
|
/** @type {!shaka.hls.Playlist} */
|
|
2268
2303
|
const playlist = this.manifestTextParser_.parsePlaylist(response.data);
|
|
2269
2304
|
|
|
2305
|
+
/** @type {!Array.<!shaka.hls.Tag>} */
|
|
2306
|
+
const variablesTags = shaka.hls.Utils.filterTagsByName(playlist.tags,
|
|
2307
|
+
'EXT-X-DEFINE');
|
|
2308
|
+
|
|
2309
|
+
const mediaVariables =
|
|
2310
|
+
this.parseMediaVariables_(variablesTags, responseUri);
|
|
2311
|
+
|
|
2270
2312
|
let mimeType = undefined;
|
|
2271
2313
|
|
|
2314
|
+
let closedCaptionsUpdated = false;
|
|
2315
|
+
|
|
2272
2316
|
// If no codec info was provided in the manifest and codec guessing is
|
|
2273
2317
|
// disabled we try to get necessary info from the media data.
|
|
2274
|
-
if (!this.codecInfoInManifest_ &&
|
|
2275
|
-
|
|
2276
|
-
|
|
2318
|
+
if ((!this.codecInfoInManifest_ &&
|
|
2319
|
+
this.config_.hls.disableCodecGuessing) ||
|
|
2320
|
+
(this.needsClosedCaptionsDetection_ && type == ContentType.VIDEO &&
|
|
2321
|
+
!this.config_.hls.disableClosedCaptionsDetection)) {
|
|
2322
|
+
this.needsClosedCaptionsDetection_ = false;
|
|
2323
|
+
|
|
2324
|
+
const basicInfo = await this.getMediaPlaylistBasicInfo_(
|
|
2325
|
+
playlist, getUris, mediaVariables);
|
|
2277
2326
|
|
|
2278
2327
|
goog.asserts.assert(
|
|
2279
2328
|
type === basicInfo.type, 'Media types should match!');
|
|
2280
2329
|
|
|
2281
|
-
|
|
2282
|
-
|
|
2330
|
+
if (basicInfo.closedCaptions.size && (!closedCaptions ||
|
|
2331
|
+
closedCaptions.size != basicInfo.closedCaptions.size)) {
|
|
2332
|
+
closedCaptions = basicInfo.closedCaptions;
|
|
2333
|
+
closedCaptionsUpdated = true;
|
|
2334
|
+
}
|
|
2335
|
+
|
|
2336
|
+
if (!this.codecInfoInManifest_ &&
|
|
2337
|
+
this.config_.hls.disableCodecGuessing) {
|
|
2338
|
+
mimeType = basicInfo.mimeType;
|
|
2339
|
+
codecs = basicInfo.codecs;
|
|
2340
|
+
}
|
|
2283
2341
|
}
|
|
2284
2342
|
|
|
2285
2343
|
const wasLive = this.isLive_();
|
|
2286
2344
|
const realStreamInfo = await this.convertParsedPlaylistIntoStreamInfo_(
|
|
2287
|
-
streamId, playlist, getUris, responseUri, codecs,
|
|
2345
|
+
streamId, mediaVariables, playlist, getUris, responseUri, codecs,
|
|
2288
2346
|
type, languageValue, primary, name, channelsCount, closedCaptions,
|
|
2289
2347
|
characteristics, forced, sampleRate, spatialAudio, mimeType);
|
|
2290
2348
|
if (abortSignal.aborted) {
|
|
@@ -2317,6 +2375,8 @@ shaka.hls.HlsParser = class {
|
|
|
2317
2375
|
stream.mimeType = realStream.mimeType;
|
|
2318
2376
|
stream.bandwidth = stream.bandwidth || realStream.bandwidth;
|
|
2319
2377
|
stream.codecs = stream.codecs || realStream.codecs;
|
|
2378
|
+
stream.closedCaptions =
|
|
2379
|
+
stream.closedCaptions || realStream.closedCaptions;
|
|
2320
2380
|
this.setFullTypeForStream_(stream);
|
|
2321
2381
|
|
|
2322
2382
|
// Since we lazy-loaded this content, the player may need to create new
|
|
@@ -2325,7 +2385,10 @@ shaka.hls.HlsParser = class {
|
|
|
2325
2385
|
this.playerInterface_.newDrmInfo(stream);
|
|
2326
2386
|
}
|
|
2327
2387
|
|
|
2328
|
-
|
|
2388
|
+
if (this.manifest_ && closedCaptionsUpdated) {
|
|
2389
|
+
this.playerInterface_.makeTextStreamsForClosedCaptions(this.manifest_);
|
|
2390
|
+
}
|
|
2391
|
+
|
|
2329
2392
|
if (type == ContentType.VIDEO || type == ContentType.AUDIO) {
|
|
2330
2393
|
for (const otherStreamInfo of this.uriToStreamInfosMap_.values()) {
|
|
2331
2394
|
if (!otherStreamInfo.loadedOnce && otherStreamInfo.type == type) {
|
|
@@ -2556,7 +2619,7 @@ shaka.hls.HlsParser = class {
|
|
|
2556
2619
|
* @return {!Promise.<!shaka.hls.HlsParser.StreamInfo>}
|
|
2557
2620
|
* @private
|
|
2558
2621
|
*/
|
|
2559
|
-
async convertParsedPlaylistIntoStreamInfo_(streamId, playlist,
|
|
2622
|
+
async convertParsedPlaylistIntoStreamInfo_(streamId, variables, playlist,
|
|
2560
2623
|
getUris, responseUri, codecs, type, languageValue, primary, name,
|
|
2561
2624
|
channelsCount, closedCaptions, characteristics, forced, sampleRate,
|
|
2562
2625
|
spatialAudio, mimeType = undefined) {
|
|
@@ -2569,13 +2632,6 @@ shaka.hls.HlsParser = class {
|
|
|
2569
2632
|
shaka.util.Error.Code.HLS_INVALID_PLAYLIST_HIERARCHY);
|
|
2570
2633
|
}
|
|
2571
2634
|
|
|
2572
|
-
/** @type {!Array.<!shaka.hls.Tag>} */
|
|
2573
|
-
const variablesTags = shaka.hls.Utils.filterTagsByName(playlist.tags,
|
|
2574
|
-
'EXT-X-DEFINE');
|
|
2575
|
-
|
|
2576
|
-
const mediaVariables =
|
|
2577
|
-
this.parseMediaVariables_(variablesTags, responseUri);
|
|
2578
|
-
|
|
2579
2635
|
goog.asserts.assert(playlist.segments != null,
|
|
2580
2636
|
'Media playlist should have segments!');
|
|
2581
2637
|
|
|
@@ -2587,11 +2643,11 @@ shaka.hls.HlsParser = class {
|
|
|
2587
2643
|
|
|
2588
2644
|
if (!mimeType) {
|
|
2589
2645
|
mimeType = await this.guessMimeType_(type, codecs, playlist,
|
|
2590
|
-
|
|
2646
|
+
variables, getUris);
|
|
2591
2647
|
}
|
|
2592
2648
|
|
|
2593
2649
|
const {drmInfos, keyIds, encrypted, aesEncrypted} =
|
|
2594
|
-
await this.parseDrmInfo_(playlist, mimeType, getUris,
|
|
2650
|
+
await this.parseDrmInfo_(playlist, mimeType, getUris, variables);
|
|
2595
2651
|
|
|
2596
2652
|
if (encrypted && !drmInfos.length && !aesEncrypted) {
|
|
2597
2653
|
throw new shaka.util.Error(
|
|
@@ -2613,8 +2669,7 @@ shaka.hls.HlsParser = class {
|
|
|
2613
2669
|
this.mediaSequenceToStartTimeByType_.get(type) : new Map();
|
|
2614
2670
|
|
|
2615
2671
|
const {segments, bandwidth} = this.createSegments_(
|
|
2616
|
-
playlist, stream, mediaSequenceToStartTime,
|
|
2617
|
-
type);
|
|
2672
|
+
playlist, stream, mediaSequenceToStartTime, variables, getUris, type);
|
|
2618
2673
|
if (bandwidth) {
|
|
2619
2674
|
stream.bandwidth = bandwidth;
|
|
2620
2675
|
}
|
|
@@ -2797,6 +2852,7 @@ shaka.hls.HlsParser = class {
|
|
|
2797
2852
|
spatialAudio,
|
|
2798
2853
|
closedCaptions,
|
|
2799
2854
|
hdr: undefined,
|
|
2855
|
+
colorGamut: undefined,
|
|
2800
2856
|
videoLayout: undefined,
|
|
2801
2857
|
tilesLayout: undefined,
|
|
2802
2858
|
accessibilityPurpose: accessibilityPurpose,
|
|
@@ -3973,16 +4029,18 @@ shaka.hls.HlsParser = class {
|
|
|
3973
4029
|
* @param {?string} frameRate
|
|
3974
4030
|
* @param {?string} videoRange
|
|
3975
4031
|
* @param {?string} videoLayout
|
|
4032
|
+
* @param {?string} colorGamut
|
|
3976
4033
|
* @private
|
|
3977
4034
|
*/
|
|
3978
4035
|
addVideoAttributes_(stream, width, height, frameRate, videoRange,
|
|
3979
|
-
videoLayout) {
|
|
4036
|
+
videoLayout, colorGamut) {
|
|
3980
4037
|
if (stream) {
|
|
3981
4038
|
stream.width = Number(width) || undefined;
|
|
3982
4039
|
stream.height = Number(height) || undefined;
|
|
3983
4040
|
stream.frameRate = Number(frameRate) || undefined;
|
|
3984
4041
|
stream.hdr = videoRange || undefined;
|
|
3985
4042
|
stream.videoLayout = videoLayout || undefined;
|
|
4043
|
+
stream.colorGamut = colorGamut || undefined;
|
|
3986
4044
|
}
|
|
3987
4045
|
}
|
|
3988
4046
|
|