shaka-player 4.7.12 → 4.7.14
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/AUTHORS +1 -0
- package/CONTRIBUTORS +1 -0
- package/dist/deps.js +3 -3
- package/dist/locales.js +34 -34
- package/dist/shaka-player.compiled.d.ts +3 -2
- package/dist/shaka-player.compiled.debug.d.ts +3 -2
- package/dist/shaka-player.compiled.debug.externs.js +4 -0
- package/dist/shaka-player.compiled.debug.js +265 -257
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +4 -0
- package/dist/shaka-player.compiled.js +1150 -1140
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +3 -2
- package/dist/shaka-player.ui.debug.d.ts +3 -2
- package/dist/shaka-player.ui.debug.externs.js +4 -0
- package/dist/shaka-player.ui.debug.js +394 -386
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +4 -0
- package/dist/shaka-player.ui.js +1306 -1296
- package/dist/shaka-player.ui.map +4 -4
- package/externs/shaka/manifest.js +11 -1
- package/externs/shaka/offline.js +7 -1
- package/lib/ads/client_side_ad_manager.js +4 -2
- package/lib/dash/dash_parser.js +10 -3
- package/lib/dash/segment_base.js +8 -1
- package/lib/dash/segment_list.js +24 -18
- package/lib/dash/segment_template.js +45 -3
- package/lib/hls/hls_parser.js +18 -1
- package/lib/media/drm_engine.js +17 -3
- package/lib/media/media_source_engine.js +87 -27
- package/lib/media/segment_index.js +31 -20
- package/lib/media/segment_reference.js +12 -0
- package/lib/media/streaming_engine.js +10 -28
- package/lib/mss/mss_parser.js +4 -0
- package/lib/offline/indexeddb/v1_storage_cell.js +2 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +2 -0
- package/lib/offline/manifest_converter.js +10 -3
- package/lib/offline/storage.js +2 -0
- package/lib/player.js +57 -17
- package/lib/text/ui_text_displayer.js +10 -1
- package/lib/util/mime_utils.js +10 -5
- package/lib/util/periods.js +5 -37
- package/lib/util/platform.js +31 -9
- package/lib/util/stream_utils.js +340 -273
- package/package.json +1 -1
- package/ui/resolution_selection.js +1 -0
|
@@ -400,7 +400,8 @@ shaka.extern.FetchCryptoKeysFunction;
|
|
|
400
400
|
* undefined),
|
|
401
401
|
* mssPrivateData: (shaka.extern.MssPrivateData|undefined),
|
|
402
402
|
* external: boolean,
|
|
403
|
-
* fastSwitching: boolean
|
|
403
|
+
* fastSwitching: boolean,
|
|
404
|
+
* fullMimeTypes: !Set.<string>
|
|
404
405
|
* }}
|
|
405
406
|
*
|
|
406
407
|
* @description
|
|
@@ -430,10 +431,14 @@ shaka.extern.FetchCryptoKeysFunction;
|
|
|
430
431
|
* @property {string} mimeType
|
|
431
432
|
* <i>Required.</i> <br>
|
|
432
433
|
* The Stream's MIME type, e.g., 'audio/mp4', 'video/webm', or 'text/vtt'.
|
|
434
|
+
* In the case of a stream that adapts between different periods with
|
|
435
|
+
* different MIME types, this represents only the first period.
|
|
433
436
|
* @property {string} codecs
|
|
434
437
|
* <i>Defaults to '' (i.e., unknown / not needed).</i> <br>
|
|
435
438
|
* The Stream's codecs, e.g., 'avc1.4d4015' or 'vp9', which must be
|
|
436
439
|
* compatible with the Stream's MIME type. <br>
|
|
440
|
+
* In the case of a stream that adapts between different periods with
|
|
441
|
+
* different codecs, this represents only the first period.
|
|
437
442
|
* See {@link https://tools.ietf.org/html/rfc6381}
|
|
438
443
|
* @property {(number|undefined)} frameRate
|
|
439
444
|
* <i>Video streams only.</i> <br>
|
|
@@ -535,6 +540,11 @@ shaka.extern.FetchCryptoKeysFunction;
|
|
|
535
540
|
* Eg: external text tracks.
|
|
536
541
|
* @property {boolean} fastSwitching
|
|
537
542
|
* Indicate if the stream should be used for fast switching.
|
|
543
|
+
* @property {!Set.<string>} fullMimeTypes
|
|
544
|
+
* A set of full MIME types (e.g. MIME types plus codecs information), that
|
|
545
|
+
* represents the types used in each period of the original manifest.
|
|
546
|
+
* Meant for being used by compatibility checking, such as with
|
|
547
|
+
* MediaSource.isTypeSupported.
|
|
538
548
|
*
|
|
539
549
|
* @exportDoc
|
|
540
550
|
*/
|
package/externs/shaka/offline.js
CHANGED
|
@@ -230,7 +230,9 @@ shaka.extern.StreamDB;
|
|
|
230
230
|
* tilesLayout: ?string,
|
|
231
231
|
* pendingSegmentRefId: (string|undefined),
|
|
232
232
|
* pendingInitSegmentRefId: (string|undefined),
|
|
233
|
-
* dataKey: number
|
|
233
|
+
* dataKey: number,
|
|
234
|
+
* mimeType: ?string,
|
|
235
|
+
* codecs: ?string
|
|
234
236
|
* }}
|
|
235
237
|
*
|
|
236
238
|
* @property {?number} initSegmentKey
|
|
@@ -263,6 +265,10 @@ shaka.extern.StreamDB;
|
|
|
263
265
|
* downloaded.
|
|
264
266
|
* @property {number} dataKey
|
|
265
267
|
* The key to the data in storage.
|
|
268
|
+
* @property {?string} mimeType
|
|
269
|
+
* The mimeType of the segment.
|
|
270
|
+
* @property {?string} codecs
|
|
271
|
+
* The codecs of the segment.
|
|
266
272
|
*/
|
|
267
273
|
shaka.extern.SegmentDB;
|
|
268
274
|
|
|
@@ -533,7 +533,9 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
533
533
|
shaka.ads.AdManager.AD_STARTED, data));
|
|
534
534
|
if (this.ad_.isLinear()) {
|
|
535
535
|
this.adContainer_.setAttribute('ad-active', 'true');
|
|
536
|
-
this.
|
|
536
|
+
if (!this.config_.customPlayheadTracker) {
|
|
537
|
+
this.video_.pause();
|
|
538
|
+
}
|
|
537
539
|
if (this.video_.muted) {
|
|
538
540
|
this.ad_.setInitialMuted(this.video_.volume);
|
|
539
541
|
} else {
|
|
@@ -551,7 +553,7 @@ shaka.ads.ClientSideAdManager = class {
|
|
|
551
553
|
(new Map()).set('originalEvent', e)));
|
|
552
554
|
if (this.ad_ && this.ad_.isLinear()) {
|
|
553
555
|
this.adContainer_.removeAttribute('ad-active');
|
|
554
|
-
if (!this.video_.ended) {
|
|
556
|
+
if (!this.config_.customPlayheadTracker && !this.video_.ended) {
|
|
555
557
|
this.video_.play();
|
|
556
558
|
}
|
|
557
559
|
}
|
package/lib/dash/dash_parser.js
CHANGED
|
@@ -1485,8 +1485,13 @@ shaka.dash.DashParser = class {
|
|
|
1485
1485
|
const getBaseUris = context.representation.getBaseUris;
|
|
1486
1486
|
streamInfo = {
|
|
1487
1487
|
generateSegmentIndex: () => {
|
|
1488
|
-
|
|
1489
|
-
periodStart, duration, getBaseUris())
|
|
1488
|
+
const segmentIndex = shaka.media.SegmentIndex.forSingleSegment(
|
|
1489
|
+
periodStart, duration, getBaseUris());
|
|
1490
|
+
segmentIndex.forEachTopLevelReference((ref) => {
|
|
1491
|
+
ref.mimeType = context.representation.mimeType;
|
|
1492
|
+
ref.codecs = context.representation.codecs;
|
|
1493
|
+
});
|
|
1494
|
+
return Promise.resolve(segmentIndex);
|
|
1490
1495
|
},
|
|
1491
1496
|
};
|
|
1492
1497
|
}
|
|
@@ -1585,7 +1590,7 @@ shaka.dash.DashParser = class {
|
|
|
1585
1590
|
},
|
|
1586
1591
|
segmentIndex: null,
|
|
1587
1592
|
mimeType: context.representation.mimeType,
|
|
1588
|
-
codecs
|
|
1593
|
+
codecs,
|
|
1589
1594
|
frameRate: context.representation.frameRate,
|
|
1590
1595
|
pixelAspectRatio: context.representation.pixelAspectRatio,
|
|
1591
1596
|
bandwidth: context.bandwidth,
|
|
@@ -1615,6 +1620,8 @@ shaka.dash.DashParser = class {
|
|
|
1615
1620
|
accessibilityPurpose,
|
|
1616
1621
|
external: false,
|
|
1617
1622
|
fastSwitching: false,
|
|
1623
|
+
fullMimeTypes: new Set([shaka.util.MimeUtils.getFullType(
|
|
1624
|
+
context.representation.mimeType, context.representation.codecs)]),
|
|
1618
1625
|
};
|
|
1619
1626
|
}
|
|
1620
1627
|
|
package/lib/dash/segment_base.js
CHANGED
|
@@ -62,7 +62,7 @@ shaka.dash.SegmentBase = class {
|
|
|
62
62
|
|
|
63
63
|
const getUris = () => resolvedUris;
|
|
64
64
|
const qualityInfo = shaka.dash.SegmentBase.createQualityInfo(context);
|
|
65
|
-
|
|
65
|
+
const ref = new shaka.media.InitSegmentReference(
|
|
66
66
|
getUris,
|
|
67
67
|
startByte,
|
|
68
68
|
endByte,
|
|
@@ -70,6 +70,9 @@ shaka.dash.SegmentBase = class {
|
|
|
70
70
|
/* timescale= */ null,
|
|
71
71
|
/* segmentData= */ null,
|
|
72
72
|
aes128Key);
|
|
73
|
+
ref.codecs = context.representation.codecs;
|
|
74
|
+
ref.mimeType = context.representation.mimeType;
|
|
75
|
+
return ref;
|
|
73
76
|
}
|
|
74
77
|
|
|
75
78
|
/**
|
|
@@ -184,6 +187,10 @@ shaka.dash.SegmentBase = class {
|
|
|
184
187
|
indexData, initData, uris, initSegmentReference, timestampOffset,
|
|
185
188
|
appendWindowStart, appendWindowEnd);
|
|
186
189
|
}
|
|
190
|
+
for (const ref of references) {
|
|
191
|
+
ref.codecs = context.representation.codecs;
|
|
192
|
+
ref.mimeType = context.representation.mimeType;
|
|
193
|
+
}
|
|
187
194
|
|
|
188
195
|
presentationTimeline.notifySegments(references);
|
|
189
196
|
|
package/lib/dash/segment_list.js
CHANGED
|
@@ -60,7 +60,8 @@ shaka.dash.SegmentList = class {
|
|
|
60
60
|
const references = SegmentList.createSegmentReferences_(
|
|
61
61
|
context.periodInfo.start, context.periodInfo.duration,
|
|
62
62
|
info.startNumber, context.representation.getBaseUris, info,
|
|
63
|
-
initSegmentReference, aes128Key
|
|
63
|
+
initSegmentReference, aes128Key, context.representation.mimeType,
|
|
64
|
+
context.representation.codecs);
|
|
64
65
|
|
|
65
66
|
const isNew = !segmentIndex;
|
|
66
67
|
if (segmentIndex) {
|
|
@@ -199,12 +200,14 @@ shaka.dash.SegmentList = class {
|
|
|
199
200
|
* @param {shaka.dash.SegmentList.SegmentListInfo} info
|
|
200
201
|
* @param {shaka.media.InitSegmentReference} initSegmentReference
|
|
201
202
|
* @param {shaka.extern.aes128Key|undefined} aes128Key
|
|
203
|
+
* @param {string} mimeType
|
|
204
|
+
* @param {string} codecs
|
|
202
205
|
* @return {!Array.<!shaka.media.SegmentReference>}
|
|
203
206
|
* @private
|
|
204
207
|
*/
|
|
205
208
|
static createSegmentReferences_(
|
|
206
209
|
periodStart, periodDuration, startNumber, getBaseUris, info,
|
|
207
|
-
initSegmentReference, aes128Key) {
|
|
210
|
+
initSegmentReference, aes128Key, mimeType, codecs) {
|
|
208
211
|
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
209
212
|
|
|
210
213
|
let max = info.mediaSegments.length;
|
|
@@ -251,22 +254,25 @@ shaka.dash.SegmentList = class {
|
|
|
251
254
|
}
|
|
252
255
|
return uris;
|
|
253
256
|
};
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
257
|
+
|
|
258
|
+
const ref = new shaka.media.SegmentReference(
|
|
259
|
+
periodStart + startTime,
|
|
260
|
+
periodStart + endTime,
|
|
261
|
+
getUris,
|
|
262
|
+
segment.start,
|
|
263
|
+
segment.end,
|
|
264
|
+
initSegmentReference,
|
|
265
|
+
timestampOffset,
|
|
266
|
+
appendWindowStart, appendWindowEnd,
|
|
267
|
+
/* partialReferences= */ [],
|
|
268
|
+
/* tilesLayout= */ '',
|
|
269
|
+
/* tileDuration= */ null,
|
|
270
|
+
/* syncTime= */ null,
|
|
271
|
+
shaka.media.SegmentReference.Status.AVAILABLE,
|
|
272
|
+
aes128Key);
|
|
273
|
+
ref.codecs = codecs;
|
|
274
|
+
ref.mimeType = mimeType;
|
|
275
|
+
references.push(ref);
|
|
270
276
|
prevEndTime = endTime;
|
|
271
277
|
}
|
|
272
278
|
|
|
@@ -213,6 +213,8 @@ shaka.dash.SegmentTemplate = class {
|
|
|
213
213
|
timeline: segmentInfo.timeline,
|
|
214
214
|
mediaTemplate: media,
|
|
215
215
|
indexTemplate: index,
|
|
216
|
+
mimeType: context.representation.mimeType,
|
|
217
|
+
codecs: context.representation.codecs,
|
|
216
218
|
};
|
|
217
219
|
}
|
|
218
220
|
|
|
@@ -392,6 +394,11 @@ shaka.dash.SegmentTemplate = class {
|
|
|
392
394
|
Math.ceil(availablePeriodTimes[1] / segmentDuration) - 1,
|
|
393
395
|
];
|
|
394
396
|
|
|
397
|
+
// For Low Latency we can request the partial current position.
|
|
398
|
+
if (context.representation.availabilityTimeOffset) {
|
|
399
|
+
availablePeriodPositions[1]++;
|
|
400
|
+
}
|
|
401
|
+
|
|
395
402
|
// In absolute positions.
|
|
396
403
|
const availablePresentationPositions =
|
|
397
404
|
availablePeriodPositions.map((x) => x + startNumber);
|
|
@@ -463,6 +470,8 @@ shaka.dash.SegmentTemplate = class {
|
|
|
463
470
|
/* syncTime= */ null,
|
|
464
471
|
shaka.media.SegmentReference.Status.AVAILABLE,
|
|
465
472
|
aes128Key);
|
|
473
|
+
ref.codecs = context.representation.codecs;
|
|
474
|
+
ref.mimeType = context.representation.mimeType;
|
|
466
475
|
// This is necessary information for thumbnail streams:
|
|
467
476
|
ref.trueEndTime = trueSegmentEnd;
|
|
468
477
|
return ref;
|
|
@@ -552,7 +561,7 @@ shaka.dash.SegmentTemplate = class {
|
|
|
552
561
|
return resolvedUris;
|
|
553
562
|
};
|
|
554
563
|
const qualityInfo = shaka.dash.SegmentBase.createQualityInfo(context);
|
|
555
|
-
|
|
564
|
+
const ref = new shaka.media.InitSegmentReference(
|
|
556
565
|
getUris,
|
|
557
566
|
/* startByte= */ 0,
|
|
558
567
|
/* endByte= */ null,
|
|
@@ -560,6 +569,9 @@ shaka.dash.SegmentTemplate = class {
|
|
|
560
569
|
/* timescale= */ null,
|
|
561
570
|
/* segmentData= */ null,
|
|
562
571
|
aes128Key);
|
|
572
|
+
ref.codecs = context.representation.codecs;
|
|
573
|
+
ref.mimeType = context.representation.mimeType;
|
|
574
|
+
return ref;
|
|
563
575
|
}
|
|
564
576
|
};
|
|
565
577
|
|
|
@@ -689,7 +701,7 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
689
701
|
*/
|
|
690
702
|
appendTemplateInfo(info, periodStart, periodEnd, shouldFit,
|
|
691
703
|
initSegmentReference) {
|
|
692
|
-
this.
|
|
704
|
+
this.updateInitSegmentReference(initSegmentReference);
|
|
693
705
|
if (!this.templateInfo_) {
|
|
694
706
|
this.templateInfo_ = info;
|
|
695
707
|
this.periodStart_ = periodStart;
|
|
@@ -720,6 +732,24 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
720
732
|
}
|
|
721
733
|
}
|
|
722
734
|
|
|
735
|
+
/**
|
|
736
|
+
* Updates the init segment reference and propagates the update to all
|
|
737
|
+
* references.
|
|
738
|
+
* @param {shaka.media.InitSegmentReference} initSegmentReference
|
|
739
|
+
*/
|
|
740
|
+
updateInitSegmentReference(initSegmentReference) {
|
|
741
|
+
if (this.initSegmentReference_ === initSegmentReference) {
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
this.initSegmentReference_ = initSegmentReference;
|
|
746
|
+
for (const reference of this.references) {
|
|
747
|
+
if (reference) {
|
|
748
|
+
reference.updateInitSegmentReference(initSegmentReference);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
723
753
|
/**
|
|
724
754
|
*
|
|
725
755
|
* @param {number} time
|
|
@@ -835,6 +865,8 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
835
865
|
this.periodEnd_ !== Infinity) {
|
|
836
866
|
segmentEnd = this.periodEnd_;
|
|
837
867
|
}
|
|
868
|
+
const codecs = this.templateInfo_.codecs;
|
|
869
|
+
const mimeType = this.templateInfo_.mimeType;
|
|
838
870
|
|
|
839
871
|
const partialSegmentRefs = [];
|
|
840
872
|
|
|
@@ -877,6 +909,8 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
877
909
|
/* syncTime= */ null,
|
|
878
910
|
shaka.media.SegmentReference.Status.AVAILABLE,
|
|
879
911
|
this.aes128Key_);
|
|
912
|
+
partial.codecs = codecs;
|
|
913
|
+
partial.mimeType = mimeType;
|
|
880
914
|
if (this.segmentSequenceCadence_ == 0) {
|
|
881
915
|
if (i > 0) {
|
|
882
916
|
partial.markAsNonIndependent();
|
|
@@ -920,6 +954,8 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
920
954
|
shaka.media.SegmentReference.Status.AVAILABLE,
|
|
921
955
|
this.aes128Key_,
|
|
922
956
|
/* allPartialSegments= */ range.partialSegments > 0);
|
|
957
|
+
ref.codecs = codecs;
|
|
958
|
+
ref.mimeType = mimeType;
|
|
923
959
|
ref.trueEndTime = trueSegmentEnd;
|
|
924
960
|
this.references[correctedPosition] = ref;
|
|
925
961
|
}
|
|
@@ -955,7 +991,9 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
955
991
|
* unscaledPresentationTimeOffset: number,
|
|
956
992
|
* timeline: Array.<shaka.media.PresentationTimeline.TimeRange>,
|
|
957
993
|
* mediaTemplate: ?string,
|
|
958
|
-
* indexTemplate: ?string
|
|
994
|
+
* indexTemplate: ?string,
|
|
995
|
+
* mimeType: string,
|
|
996
|
+
* codecs: string
|
|
959
997
|
* }}
|
|
960
998
|
*
|
|
961
999
|
* @description
|
|
@@ -977,5 +1015,9 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
977
1015
|
* The media URI template, if given.
|
|
978
1016
|
* @property {?string} indexTemplate
|
|
979
1017
|
* The index URI template, if given.
|
|
1018
|
+
* @property {string} mimeType
|
|
1019
|
+
* The mimeType.
|
|
1020
|
+
* @property {string} codecs
|
|
1021
|
+
* The codecs.
|
|
980
1022
|
*/
|
|
981
1023
|
shaka.dash.SegmentTemplate.SegmentTemplateInfo;
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -1224,6 +1224,7 @@ shaka.hls.HlsParser = class {
|
|
|
1224
1224
|
textStreamInfo.stream.mimeType =
|
|
1225
1225
|
this.guessMimeTypeBeforeLoading_(type, codecs) ||
|
|
1226
1226
|
this.guessMimeTypeFallback_(type);
|
|
1227
|
+
this.setFullTypeForStream_(textStreamInfo.stream);
|
|
1227
1228
|
}
|
|
1228
1229
|
}
|
|
1229
1230
|
}
|
|
@@ -1233,6 +1234,15 @@ shaka.hls.HlsParser = class {
|
|
|
1233
1234
|
return textStreams.filter((s) => s);
|
|
1234
1235
|
}
|
|
1235
1236
|
|
|
1237
|
+
/**
|
|
1238
|
+
* @param {!shaka.extern.Stream} stream
|
|
1239
|
+
* @private
|
|
1240
|
+
*/
|
|
1241
|
+
setFullTypeForStream_(stream) {
|
|
1242
|
+
stream.fullMimeTypes = new Set([shaka.util.MimeUtils.getFullType(
|
|
1243
|
+
stream.mimeType, stream.codecs)]);
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1236
1246
|
/**
|
|
1237
1247
|
* @param {!Array.<!shaka.hls.Tag>} imageTags from the playlist.
|
|
1238
1248
|
* @param {!Array.<!shaka.hls.Tag>} iFrameTags from the playlist.
|
|
@@ -2266,6 +2276,7 @@ shaka.hls.HlsParser = class {
|
|
|
2266
2276
|
stream.mimeType = realStream.mimeType;
|
|
2267
2277
|
stream.bandwidth = stream.bandwidth || realStream.bandwidth;
|
|
2268
2278
|
stream.codecs = stream.codecs || realStream.codecs;
|
|
2279
|
+
this.setFullTypeForStream_(stream);
|
|
2269
2280
|
|
|
2270
2281
|
// Since we lazy-loaded this content, the player may need to create new
|
|
2271
2282
|
// sessions for the DRM info in this stream.
|
|
@@ -2280,6 +2291,7 @@ shaka.hls.HlsParser = class {
|
|
|
2280
2291
|
// To aid manifest filtering, assume before loading that all video
|
|
2281
2292
|
// renditions have the same MIME type. (And likewise for audio.)
|
|
2282
2293
|
otherStreamInfo.stream.mimeType = realStream.mimeType;
|
|
2294
|
+
this.setFullTypeForStream_(otherStreamInfo.stream);
|
|
2283
2295
|
}
|
|
2284
2296
|
}
|
|
2285
2297
|
}
|
|
@@ -2288,6 +2300,7 @@ shaka.hls.HlsParser = class {
|
|
|
2288
2300
|
const firstSegment = realStream.segmentIndex.get(0);
|
|
2289
2301
|
if (firstSegment && firstSegment.initSegmentReference) {
|
|
2290
2302
|
stream.mimeType = 'application/mp4';
|
|
2303
|
+
this.setFullTypeForStream_(stream);
|
|
2291
2304
|
}
|
|
2292
2305
|
}
|
|
2293
2306
|
|
|
@@ -2537,6 +2550,7 @@ shaka.hls.HlsParser = class {
|
|
|
2537
2550
|
stream.drmInfos = drmInfos;
|
|
2538
2551
|
stream.keyIds = keyIds;
|
|
2539
2552
|
stream.mimeType = mimeType;
|
|
2553
|
+
this.setFullTypeForStream_(stream);
|
|
2540
2554
|
|
|
2541
2555
|
const mediaSequenceToStartTime = this.isLive_() ?
|
|
2542
2556
|
this.mediaSequenceToStartTimeByType_.get(type) : new Map();
|
|
@@ -2692,7 +2706,7 @@ shaka.hls.HlsParser = class {
|
|
|
2692
2706
|
roles.push(shaka.util.ManifestParserUtils.TextStreamKind.SUBTITLE);
|
|
2693
2707
|
}
|
|
2694
2708
|
|
|
2695
|
-
|
|
2709
|
+
const stream = {
|
|
2696
2710
|
id: this.globalId_++,
|
|
2697
2711
|
originalId: name,
|
|
2698
2712
|
groupId: null,
|
|
@@ -2730,7 +2744,10 @@ shaka.hls.HlsParser = class {
|
|
|
2730
2744
|
accessibilityPurpose: accessibilityPurpose,
|
|
2731
2745
|
external: false,
|
|
2732
2746
|
fastSwitching: false,
|
|
2747
|
+
fullMimeTypes: new Set(),
|
|
2733
2748
|
};
|
|
2749
|
+
this.setFullTypeForStream_(stream);
|
|
2750
|
+
return stream;
|
|
2734
2751
|
}
|
|
2735
2752
|
|
|
2736
2753
|
/**
|
package/lib/media/drm_engine.js
CHANGED
|
@@ -1551,6 +1551,9 @@ shaka.media.DrmEngine = class {
|
|
|
1551
1551
|
const req = this.playerInterface_.netEngine.request(requestType, request);
|
|
1552
1552
|
response = await req.promise;
|
|
1553
1553
|
} catch (error) {
|
|
1554
|
+
if (this.destroyer_.destroyed()) {
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1554
1557
|
// Request failed!
|
|
1555
1558
|
goog.asserts.assert(error instanceof shaka.util.Error,
|
|
1556
1559
|
'Wrong NetworkingEngine error type!');
|
|
@@ -1559,9 +1562,20 @@ shaka.media.DrmEngine = class {
|
|
|
1559
1562
|
shaka.util.Error.Category.DRM,
|
|
1560
1563
|
shaka.util.Error.Code.LICENSE_REQUEST_FAILED,
|
|
1561
1564
|
error);
|
|
1562
|
-
this.
|
|
1563
|
-
|
|
1564
|
-
metadata.updatePromise
|
|
1565
|
+
if (this.activeSessions_.size == 1) {
|
|
1566
|
+
this.onError_(shakaErr);
|
|
1567
|
+
if (metadata && metadata.updatePromise) {
|
|
1568
|
+
metadata.updatePromise.reject(shakaErr);
|
|
1569
|
+
}
|
|
1570
|
+
} else {
|
|
1571
|
+
if (metadata && metadata.updatePromise) {
|
|
1572
|
+
metadata.updatePromise.reject(shakaErr);
|
|
1573
|
+
}
|
|
1574
|
+
this.activeSessions_.delete(session);
|
|
1575
|
+
if (this.areAllSessionsLoaded_()) {
|
|
1576
|
+
this.allSessionsLoaded_.resolve();
|
|
1577
|
+
this.keyStatusTimer_.tickAfter(/* seconds= */ 0.1);
|
|
1578
|
+
}
|
|
1565
1579
|
}
|
|
1566
1580
|
return;
|
|
1567
1581
|
}
|
|
@@ -31,6 +31,7 @@ goog.require('shaka.util.Mp4BoxParsers');
|
|
|
31
31
|
goog.require('shaka.util.Mp4Parser');
|
|
32
32
|
goog.require('shaka.util.Platform');
|
|
33
33
|
goog.require('shaka.util.PublicPromise');
|
|
34
|
+
goog.require('shaka.util.StreamUtils');
|
|
34
35
|
goog.require('shaka.util.TsParser');
|
|
35
36
|
goog.require('shaka.lcevc.Dec');
|
|
36
37
|
|
|
@@ -237,18 +238,61 @@ shaka.media.MediaSourceEngine = class {
|
|
|
237
238
|
* Checks if a certain type is supported.
|
|
238
239
|
*
|
|
239
240
|
* @param {shaka.extern.Stream} stream
|
|
240
|
-
* @
|
|
241
|
+
* @param {shaka.util.ManifestParserUtils.ContentType} contentType
|
|
242
|
+
* @return {!Promise.<boolean>}
|
|
241
243
|
*/
|
|
242
|
-
static isStreamSupported(stream) {
|
|
244
|
+
static async isStreamSupported(stream, contentType) {
|
|
245
|
+
if (stream.createSegmentIndex) {
|
|
246
|
+
await stream.createSegmentIndex();
|
|
247
|
+
}
|
|
248
|
+
if (!stream.segmentIndex) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
if (stream.segmentIndex.isEmpty()) {
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
243
254
|
const MimeUtils = shaka.util.MimeUtils;
|
|
244
|
-
const fullMimeType = MimeUtils.getFullType(stream.mimeType, stream.codecs);
|
|
245
|
-
const extendedMimeType = MimeUtils.getExtendedType(stream);
|
|
246
|
-
const fullMimeTypeWithAllCodecs = MimeUtils.getFullTypeWithAllCodecs(
|
|
247
|
-
stream.mimeType, stream.codecs);
|
|
248
255
|
const TransmuxerEngine = shaka.transmuxer.TransmuxerEngine;
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
256
|
+
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
257
|
+
const StreamUtils = shaka.util.StreamUtils;
|
|
258
|
+
const seenCombos = new Set();
|
|
259
|
+
// Check each combination of mimeType and codecs within the segment index.
|
|
260
|
+
// Unfortunately we cannot use fullMimeTypes, as we ALSO need to check the
|
|
261
|
+
// getFullTypeWithAllCodecs (for the sake of the transmuxer) and we have no
|
|
262
|
+
// way of going from a full mimeType to a full mimeType with all codecs.
|
|
263
|
+
// As this function is only called in debug mode, a little inefficiency is
|
|
264
|
+
// acceptable.
|
|
265
|
+
for (const ref of stream.segmentIndex) {
|
|
266
|
+
const mimeType = ref.mimeType || stream.mimeType || '';
|
|
267
|
+
let codecs = ref.codecs || stream.codecs || '';
|
|
268
|
+
// Don't check the same combination of mimetype + codecs twice.
|
|
269
|
+
const combo = mimeType + ':' + codecs;
|
|
270
|
+
if (seenCombos.has(combo)) {
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
seenCombos.add(combo);
|
|
274
|
+
if (contentType == ContentType.TEXT) {
|
|
275
|
+
const fullMimeType = MimeUtils.getFullType(mimeType, codecs);
|
|
276
|
+
if (!shaka.text.TextEngine.isTypeSupported(fullMimeType)) {
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
} else {
|
|
280
|
+
if (contentType == ContentType.VIDEO) {
|
|
281
|
+
codecs = StreamUtils.getCorrectVideoCodecs(codecs);
|
|
282
|
+
} else if (contentType == ContentType.AUDIO) {
|
|
283
|
+
codecs = StreamUtils.getCorrectAudioCodecs(codecs);
|
|
284
|
+
}
|
|
285
|
+
const extendedMimeType = MimeUtils.getExtendedType(
|
|
286
|
+
stream, mimeType, codecs);
|
|
287
|
+
const fullMimeType = MimeUtils.getFullTypeWithAllCodecs(
|
|
288
|
+
mimeType, codecs);
|
|
289
|
+
if (!shaka.media.Capabilities.isTypeSupported(extendedMimeType) &&
|
|
290
|
+
!TransmuxerEngine.isSupported(fullMimeType, stream.type)) {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return true;
|
|
252
296
|
}
|
|
253
297
|
|
|
254
298
|
/**
|
|
@@ -451,7 +495,8 @@ shaka.media.MediaSourceEngine = class {
|
|
|
451
495
|
|
|
452
496
|
for (const contentType of streamsByType.keys()) {
|
|
453
497
|
const stream = streamsByType.get(contentType);
|
|
454
|
-
|
|
498
|
+
// eslint-disable-next-line no-await-in-loop
|
|
499
|
+
await this.initSourceBuffer_(contentType, stream, stream.codecs);
|
|
455
500
|
if (this.needSplitMuxedContent_) {
|
|
456
501
|
this.queues_[ContentType.AUDIO] = [];
|
|
457
502
|
this.queues_[ContentType.VIDEO] = [];
|
|
@@ -467,13 +512,15 @@ shaka.media.MediaSourceEngine = class {
|
|
|
467
512
|
* @param {shaka.util.ManifestParserUtils.ContentType} contentType
|
|
468
513
|
* @param {shaka.extern.Stream} stream
|
|
469
514
|
* @param {string} codecs
|
|
515
|
+
* @return {!Promise}
|
|
470
516
|
* @private
|
|
471
517
|
*/
|
|
472
|
-
initSourceBuffer_(contentType, stream, codecs) {
|
|
518
|
+
async initSourceBuffer_(contentType, stream, codecs) {
|
|
473
519
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
474
520
|
|
|
475
521
|
goog.asserts.assert(
|
|
476
|
-
shaka.media.MediaSourceEngine.isStreamSupported(
|
|
522
|
+
await shaka.media.MediaSourceEngine.isStreamSupported(
|
|
523
|
+
stream, contentType),
|
|
477
524
|
'Type negotiation should happen before MediaSourceEngine.init!');
|
|
478
525
|
|
|
479
526
|
let mimeType = shaka.util.MimeUtils.getFullType(
|
|
@@ -490,7 +537,6 @@ shaka.media.MediaSourceEngine = class {
|
|
|
490
537
|
const mimeTypeWithAllCodecs =
|
|
491
538
|
shaka.util.MimeUtils.getFullTypeWithAllCodecs(
|
|
492
539
|
stream.mimeType, codecs);
|
|
493
|
-
const TransmuxerEngine = shaka.transmuxer.TransmuxerEngine;
|
|
494
540
|
if (needTransmux) {
|
|
495
541
|
const audioCodec = shaka.util.ManifestParserUtils.guessCodecsSafe(
|
|
496
542
|
ContentType.AUDIO, (codecs || '').split(','));
|
|
@@ -498,12 +544,12 @@ shaka.media.MediaSourceEngine = class {
|
|
|
498
544
|
ContentType.VIDEO, (codecs || '').split(','));
|
|
499
545
|
if (audioCodec && videoCodec) {
|
|
500
546
|
this.needSplitMuxedContent_ = true;
|
|
501
|
-
this.initSourceBuffer_(ContentType.AUDIO, stream, audioCodec);
|
|
502
|
-
this.initSourceBuffer_(ContentType.VIDEO, stream, videoCodec);
|
|
547
|
+
await this.initSourceBuffer_(ContentType.AUDIO, stream, audioCodec);
|
|
548
|
+
await this.initSourceBuffer_(ContentType.VIDEO, stream, videoCodec);
|
|
503
549
|
return;
|
|
504
550
|
}
|
|
505
|
-
const transmuxerPlugin =
|
|
506
|
-
|
|
551
|
+
const transmuxerPlugin = shaka.transmuxer.TransmuxerEngine
|
|
552
|
+
.findTransmuxer(mimeTypeWithAllCodecs);
|
|
507
553
|
if (transmuxerPlugin) {
|
|
508
554
|
const transmuxer = transmuxerPlugin();
|
|
509
555
|
this.transmuxers_[contentType] = transmuxer;
|
|
@@ -1793,16 +1839,22 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1793
1839
|
|
|
1794
1840
|
const totalOfBuffers = streamsByType.size;
|
|
1795
1841
|
let numberOfSourceBufferAdded = 0;
|
|
1796
|
-
|
|
1842
|
+
const onSourceBufferAdded = () => {
|
|
1797
1843
|
numberOfSourceBufferAdded++;
|
|
1798
1844
|
if (numberOfSourceBufferAdded === totalOfBuffers) {
|
|
1799
1845
|
sourceBufferAdded.resolve();
|
|
1846
|
+
this.eventManager_.unlisten(sourceBuffers, 'addsourcebuffer',
|
|
1847
|
+
onSourceBufferAdded);
|
|
1800
1848
|
}
|
|
1801
|
-
}
|
|
1849
|
+
};
|
|
1850
|
+
|
|
1851
|
+
this.eventManager_.listen(sourceBuffers, 'addsourcebuffer',
|
|
1852
|
+
onSourceBufferAdded);
|
|
1802
1853
|
|
|
1803
1854
|
for (const contentType of streamsByType.keys()) {
|
|
1804
1855
|
const stream = streamsByType.get(contentType);
|
|
1805
|
-
|
|
1856
|
+
// eslint-disable-next-line no-await-in-loop
|
|
1857
|
+
await this.initSourceBuffer_(contentType, stream, stream.codecs);
|
|
1806
1858
|
if (this.needSplitMuxedContent_) {
|
|
1807
1859
|
this.queues_[ContentType.AUDIO] = [];
|
|
1808
1860
|
this.queues_[ContentType.VIDEO] = [];
|
|
@@ -1821,7 +1873,12 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1821
1873
|
this.destroyer_.ensureNotDestroyed();
|
|
1822
1874
|
|
|
1823
1875
|
this.eventManager_.listenOnce(this.video_, 'canplaythrough', () => {
|
|
1824
|
-
|
|
1876
|
+
// Don't use ensureNotDestroyed() from this event listener, because
|
|
1877
|
+
// that results in an uncaught exception. Instead, just check the
|
|
1878
|
+
// flag.
|
|
1879
|
+
if (this.destroyer_.destroyed()) {
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1825
1882
|
|
|
1826
1883
|
this.video_.autoplay = previousAutoPlayState;
|
|
1827
1884
|
if (!previousPausedState) {
|
|
@@ -1935,10 +1992,12 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1935
1992
|
*
|
|
1936
1993
|
* @param {shaka.util.ManifestParserUtils.ContentType} contentType
|
|
1937
1994
|
* @param {shaka.extern.Stream} stream
|
|
1995
|
+
* @param {string} refMimeType
|
|
1996
|
+
* @param {string} refCodecs
|
|
1938
1997
|
* @return {boolean}
|
|
1939
1998
|
* @private
|
|
1940
1999
|
*/
|
|
1941
|
-
isCodecSwitchNecessary_(contentType, stream) {
|
|
2000
|
+
isCodecSwitchNecessary_(contentType, stream, refMimeType, refCodecs) {
|
|
1942
2001
|
if (contentType == shaka.util.ManifestParserUtils.ContentType.TEXT) {
|
|
1943
2002
|
return false;
|
|
1944
2003
|
}
|
|
@@ -1948,8 +2007,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1948
2007
|
const currentBasicType = MimeUtils.getBasicType(
|
|
1949
2008
|
this.sourceBufferTypes_[contentType]);
|
|
1950
2009
|
|
|
1951
|
-
let newMimeType = shaka.util.MimeUtils.getFullType(
|
|
1952
|
-
stream.mimeType, stream.codecs);
|
|
2010
|
+
let newMimeType = shaka.util.MimeUtils.getFullType(refMimeType, refCodecs);
|
|
1953
2011
|
let needTransmux = this.config_.forceTransmux;
|
|
1954
2012
|
if (!shaka.media.Capabilities.isTypeSupported(newMimeType) ||
|
|
1955
2013
|
(!this.sequenceMode_ &&
|
|
@@ -1958,7 +2016,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1958
2016
|
}
|
|
1959
2017
|
const newMimeTypeWithAllCodecs =
|
|
1960
2018
|
shaka.util.MimeUtils.getFullTypeWithAllCodecs(
|
|
1961
|
-
|
|
2019
|
+
refMimeType, refCodecs);
|
|
1962
2020
|
const TransmuxerEngine = shaka.transmuxer.TransmuxerEngine;
|
|
1963
2021
|
if (needTransmux) {
|
|
1964
2022
|
const transmuxerPlugin =
|
|
@@ -1984,10 +2042,12 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1984
2042
|
*
|
|
1985
2043
|
* @param {shaka.util.ManifestParserUtils.ContentType} contentType
|
|
1986
2044
|
* @param {shaka.extern.Stream} stream
|
|
2045
|
+
* @param {string} mimeType
|
|
2046
|
+
* @param {string} codecs
|
|
1987
2047
|
* @return {boolean}
|
|
1988
2048
|
*/
|
|
1989
|
-
isResetMediaSourceNecessary(contentType, stream) {
|
|
1990
|
-
if (!this.isCodecSwitchNecessary_(contentType, stream)) {
|
|
2049
|
+
isResetMediaSourceNecessary(contentType, stream, mimeType, codecs) {
|
|
2050
|
+
if (!this.isCodecSwitchNecessary_(contentType, stream, mimeType, codecs)) {
|
|
1991
2051
|
return false;
|
|
1992
2052
|
}
|
|
1993
2053
|
|