shaka-player 4.3.4 → 4.3.6
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/.github/workflows/build-and-test.yaml +4 -4
- package/.github/workflows/demo-version-index.yaml +6 -0
- package/.github/workflows/selenium-lab-tests.yaml +78 -17
- package/.github/workflows/update-screenshots.yaml +142 -0
- package/AUTHORS +2 -1
- package/CHANGELOG.md +56 -0
- package/CONTRIBUTORS +4 -1
- package/demo/common/asset.js +15 -0
- package/demo/common/assets.js +4 -2
- package/demo/common/message_ids.js +1 -0
- package/demo/custom.js +19 -0
- package/demo/locales/en.json +1 -0
- package/demo/locales/source.json +4 -0
- package/demo/main.js +14 -0
- package/dist/controls.css +2 -2
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +184 -311
- package/dist/demo.compiled.debug.map +4 -4
- package/dist/demo.compiled.js +184 -311
- package/dist/demo.compiled.map +4 -4
- package/dist/deps.js +2 -2
- package/dist/locales.js +29 -29
- package/dist/receiver.compiled.debug.js +51 -80
- package/dist/receiver.compiled.debug.map +4 -4
- package/dist/receiver.compiled.js +51 -80
- package/dist/receiver.compiled.map +4 -4
- package/dist/shaka-player.compiled.d.ts +19 -3
- package/dist/shaka-player.compiled.debug.d.ts +19 -3
- package/dist/shaka-player.compiled.debug.externs.js +20 -14
- package/dist/shaka-player.compiled.debug.js +291 -283
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +20 -14
- package/dist/shaka-player.compiled.js +830 -825
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.d.ts +19 -3
- package/dist/shaka-player.ui.debug.d.ts +19 -3
- package/dist/shaka-player.ui.debug.externs.js +8 -2
- package/dist/shaka-player.ui.debug.js +301 -292
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +8 -2
- package/dist/shaka-player.ui.js +927 -922
- package/dist/shaka-player.ui.map +3 -3
- package/docs/tutorials/a11y.md +0 -4
- package/docs/tutorials/ad_monetization.md +0 -4
- package/docs/tutorials/basic-usage.md +0 -5
- package/docs/tutorials/config.md +0 -5
- package/docs/tutorials/debugging.md +0 -5
- package/docs/tutorials/drm-config.md +0 -5
- package/docs/tutorials/errors.md +94 -0
- package/docs/tutorials/fairplay.md +4 -4
- package/docs/tutorials/index.json +2 -0
- package/docs/tutorials/license-server-auth.md +0 -5
- package/docs/tutorials/license-wrapping.md +0 -5
- package/docs/tutorials/network-and-buffering-config.md +0 -5
- package/docs/tutorials/ui-customization.md +0 -5
- package/docs/tutorials/ui.md +0 -7
- package/docs/tutorials/welcome.md +0 -5
- package/docs/tutorials/widevine-service-certs.md +45 -0
- package/externs/ima.js +9 -0
- package/externs/network_information.js +7 -2
- package/externs/shaka/abr_manager.js +6 -0
- package/externs/shaka/net.js +1 -0
- package/externs/shaka/player.js +13 -7
- package/lib/abr/simple_abr_manager.js +27 -3
- package/lib/ads/client_side_ad_manager.js +11 -5
- package/lib/dash/dash_parser.js +49 -48
- package/lib/debug/log.js +9 -13
- package/lib/hls/hls_parser.js +23 -6
- package/lib/media/drm_engine.js +4 -2
- package/lib/media/media_source_engine.js +27 -9
- package/lib/media/presentation_timeline.js +9 -2
- package/lib/media/segment_index.js +2 -0
- package/lib/media/segment_reference.js +3 -2
- package/lib/media/streaming_engine.js +31 -7
- package/lib/media/transmuxer.js +13 -7
- package/lib/media/video_wrapper.js +3 -3
- package/lib/net/http_fetch_plugin.js +79 -57
- package/lib/net/networking_engine.js +1 -0
- package/lib/offline/indexeddb/storage_mechanism.js +1 -1
- package/lib/player.js +24 -3
- package/lib/polyfill/media_capabilities.js +15 -8
- package/lib/polyfill/mediasource.js +24 -2
- package/lib/text/mp4_vtt_parser.js +4 -0
- package/lib/text/text_engine.js +1 -0
- package/lib/text/ui_text_displayer.js +1 -0
- package/lib/text/vtt_text_parser.js +4 -5
- package/lib/util/manifest_parser_utils.js +1 -2
- package/lib/util/mime_utils.js +12 -1
- package/lib/util/periods.js +5 -5
- package/lib/util/stream_utils.js +28 -16
- package/maintained-branches.md +2 -3
- package/package.json +1 -1
- package/test/dash/dash_parser_live_unit.js +3 -2
- package/test/hls/hls_parser_unit.js +156 -0
- package/test/media/content_workarounds_unit.js +43 -0
- package/test/media/drm_engine_integration.js +4 -17
- package/test/media/streaming_engine_unit.js +6 -1
- package/test/net/networking_engine_unit.js +6 -1
- package/test/player_integration.js +39 -0
- package/test/player_unit.js +57 -0
- package/test/polyfill/media_capabilities_unit.js +22 -22
- package/test/test/assets/text-clip-alt.vtt +63 -0
- package/test/test/util/fake_drm_engine.js +3 -0
- package/test/test/util/fake_media_source_engine.js +4 -0
- package/test/test/util/simple_fakes.js +6 -0
- package/test/test/util/test_scheme.js +9 -14
- package/test/text/mp4_vtt_parser_unit.js +8 -0
- package/test/text/vtt_text_parser_unit.js +26 -2
- package/test/text/web_vtt_layout_integration.js +0 -3
- package/test/util/mime_utils_unit.js +10 -0
- package/ui/less/containers.less +4 -0
|
@@ -9,7 +9,6 @@ goog.provide('shaka.polyfill.MediaCapabilities');
|
|
|
9
9
|
goog.require('shaka.log');
|
|
10
10
|
goog.require('shaka.media.Capabilities');
|
|
11
11
|
goog.require('shaka.polyfill');
|
|
12
|
-
goog.require('shaka.util.Error');
|
|
13
12
|
goog.require('shaka.util.Platform');
|
|
14
13
|
|
|
15
14
|
|
|
@@ -120,6 +119,19 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
120
119
|
if (shaka.util.Platform.isChromecast()) {
|
|
121
120
|
isSupported =
|
|
122
121
|
shaka.polyfill.MediaCapabilities.canCastDisplayType_(videoConfig);
|
|
122
|
+
} else if (shaka.util.Platform.isTizen()) {
|
|
123
|
+
let extendedType = videoConfig.contentType;
|
|
124
|
+
if (videoConfig.width && videoConfig.height) {
|
|
125
|
+
extendedType += `; width=${videoConfig.width}`;
|
|
126
|
+
extendedType += `; height=${videoConfig.height}`;
|
|
127
|
+
}
|
|
128
|
+
if (videoConfig.framerate) {
|
|
129
|
+
extendedType += `; framerate=${videoConfig.framerate}`;
|
|
130
|
+
}
|
|
131
|
+
if (videoConfig.bitrate) {
|
|
132
|
+
extendedType += `; bitrate=${videoConfig.bitrate}`;
|
|
133
|
+
}
|
|
134
|
+
isSupported = Capabilities.isTypeSupported(extendedType);
|
|
123
135
|
} else {
|
|
124
136
|
isSupported = Capabilities.isTypeSupported(videoConfig.contentType);
|
|
125
137
|
}
|
|
@@ -230,13 +242,8 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
230
242
|
* @private
|
|
231
243
|
*/
|
|
232
244
|
static canCastDisplayType_(videoConfig) {
|
|
233
|
-
if (!(window.cast
|
|
234
|
-
|
|
235
|
-
throw new shaka.util.Error(
|
|
236
|
-
shaka.util.Error.Severity.CRITICAL,
|
|
237
|
-
shaka.util.Error.Category.CAST,
|
|
238
|
-
shaka.util.Error.Code.CAST_API_UNAVAILABLE);
|
|
239
|
-
} else if (!(cast.__platform__ && cast.__platform__.canDisplayType)) {
|
|
245
|
+
if (!(window.cast &&
|
|
246
|
+
cast.__platform__ && cast.__platform__.canDisplayType)) {
|
|
240
247
|
shaka.log.warning('Expected cast APIs to be available! Falling back to ' +
|
|
241
248
|
'shaka.media.Capabilities.isTypeSupported() for type support.');
|
|
242
249
|
return shaka.media.Capabilities.isTypeSupported(videoConfig.contentType);
|
|
@@ -53,14 +53,19 @@ shaka.polyfill.MediaSource = class {
|
|
|
53
53
|
// Offsetting the end of the removal range seems to help.
|
|
54
54
|
// Bug filed: https://bugs.webkit.org/show_bug.cgi?id=177884
|
|
55
55
|
shaka.polyfill.MediaSource.patchRemovalRange_();
|
|
56
|
-
} else {
|
|
57
|
-
shaka.log.info('Patching Safari 13 MSE bugs.');
|
|
56
|
+
} else if (safariVersion <= 15) {
|
|
57
|
+
shaka.log.info('Patching Safari 13 & 14 & 15 MSE bugs.');
|
|
58
58
|
// Safari 13 does not correctly implement abort() on SourceBuffer.
|
|
59
59
|
// Calling abort() before appending a segment causes that segment to be
|
|
60
60
|
// incomplete in the buffer.
|
|
61
61
|
// Bug filed: https://bugs.webkit.org/show_bug.cgi?id=165342
|
|
62
62
|
shaka.polyfill.MediaSource.stubAbort_();
|
|
63
63
|
}
|
|
64
|
+
} else if (shaka.util.Platform.isEdge()) {
|
|
65
|
+
shaka.log.info('Rejecting TS container.');
|
|
66
|
+
// TS content is broken on Edge in general.
|
|
67
|
+
// See https://github.com/shaka-project/shaka-player/issues/4955
|
|
68
|
+
shaka.polyfill.MediaSource.rejectContainer_('mp2t');
|
|
64
69
|
} else if (shaka.util.Platform.isTizen2() ||
|
|
65
70
|
shaka.util.Platform.isTizen3() ||
|
|
66
71
|
shaka.util.Platform.isTizen4()) {
|
|
@@ -122,6 +127,23 @@ shaka.polyfill.MediaSource = class {
|
|
|
122
127
|
};
|
|
123
128
|
}
|
|
124
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Patch |MediaSource.isTypeSupported| to always reject |container|. This is
|
|
132
|
+
* used when we know that we are on a platform that does not work well with
|
|
133
|
+
* a given container.
|
|
134
|
+
*
|
|
135
|
+
* @param {string} container
|
|
136
|
+
* @private
|
|
137
|
+
*/
|
|
138
|
+
static rejectContainer_(container) {
|
|
139
|
+
const isTypeSupported = MediaSource.isTypeSupported;
|
|
140
|
+
|
|
141
|
+
MediaSource.isTypeSupported = (mimeType) => {
|
|
142
|
+
const actualContainer = shaka.util.MimeUtils.getContainerType(mimeType);
|
|
143
|
+
return actualContainer != container && isTypeSupported(mimeType);
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
125
147
|
/**
|
|
126
148
|
* Patch |MediaSource.isTypeSupported| to always reject |codec|. This is used
|
|
127
149
|
* when we know that we are on a platform that does not work well with a given
|
package/lib/text/text_engine.js
CHANGED
|
@@ -139,6 +139,7 @@ shaka.text.TextEngine = class {
|
|
|
139
139
|
// into TextEngine and TextDisplayer.
|
|
140
140
|
if (mimeType == shaka.util.MimeUtils.CEA608_CLOSED_CAPTION_MIMETYPE ||
|
|
141
141
|
mimeType == shaka.util.MimeUtils.CEA708_CLOSED_CAPTION_MIMETYPE) {
|
|
142
|
+
this.parser_ = null;
|
|
142
143
|
return;
|
|
143
144
|
}
|
|
144
145
|
|
|
@@ -474,6 +474,7 @@ shaka.text.UITextDisplayer = class {
|
|
|
474
474
|
wrapper = shaka.util.Dom.createHTMLElement('span');
|
|
475
475
|
wrapper.classList.add('shaka-text-wrapper');
|
|
476
476
|
wrapper.style.backgroundColor = cue.backgroundColor;
|
|
477
|
+
wrapper.style.lineHeight = 'normal';
|
|
477
478
|
cueElement.appendChild(wrapper);
|
|
478
479
|
}
|
|
479
480
|
|
|
@@ -391,8 +391,7 @@ shaka.text.VttTextParser = class {
|
|
|
391
391
|
end += timeOffset;
|
|
392
392
|
|
|
393
393
|
// Get the payload.
|
|
394
|
-
const payload =
|
|
395
|
-
text.slice(1).join('\n').trim());
|
|
394
|
+
const payload = text.slice(1).join('\n').trim();
|
|
396
395
|
|
|
397
396
|
let cue = null;
|
|
398
397
|
if (styles.has('global')) {
|
|
@@ -450,7 +449,7 @@ shaka.text.VttTextParser = class {
|
|
|
450
449
|
const childNode = childNodes[0];
|
|
451
450
|
if (childNode.nodeType == Node.TEXT_NODE ||
|
|
452
451
|
childNode.nodeType == Node.CDATA_SECTION_NODE) {
|
|
453
|
-
rootCue.payload = payload;
|
|
452
|
+
rootCue.payload = VttTextParser.htmlUnescape_(payload);
|
|
454
453
|
return;
|
|
455
454
|
}
|
|
456
455
|
}
|
|
@@ -461,7 +460,7 @@ shaka.text.VttTextParser = class {
|
|
|
461
460
|
rootCue.nestedCues = cues;
|
|
462
461
|
} else {
|
|
463
462
|
shaka.log.warning('The cue\'s markup could not be parsed: ', payload);
|
|
464
|
-
rootCue.payload = payload;
|
|
463
|
+
rootCue.payload = VttTextParser.htmlUnescape_(payload);
|
|
465
464
|
}
|
|
466
465
|
}
|
|
467
466
|
|
|
@@ -755,7 +754,7 @@ shaka.text.VttTextParser = class {
|
|
|
755
754
|
}
|
|
756
755
|
if (text.length > 0) {
|
|
757
756
|
const textCue = nestedCue.clone();
|
|
758
|
-
textCue.payload = text;
|
|
757
|
+
textCue.payload = VttTextParser.htmlUnescape_(text);
|
|
759
758
|
cues.push(textCue);
|
|
760
759
|
}
|
|
761
760
|
isFirst = false;
|
|
@@ -185,8 +185,7 @@ shaka.util.ManifestParserUtils.AUDIO_CODEC_REGEXPS_ = [
|
|
|
185
185
|
/^mp4a/,
|
|
186
186
|
/^[ae]c-3$/,
|
|
187
187
|
/^ac-4$/,
|
|
188
|
-
/^dts[
|
|
189
|
-
/^[du]dts$/, // DTS Surround Sound
|
|
188
|
+
/^dts[cex]$/, // DTS Digital Surround (dtsc), DTS Express (dtse), DTS:X (dtsx)
|
|
190
189
|
];
|
|
191
190
|
|
|
192
191
|
|
package/lib/util/mime_utils.js
CHANGED
|
@@ -49,7 +49,7 @@ shaka.util.MimeUtils = class {
|
|
|
49
49
|
|
|
50
50
|
if (Transmuxer.isSupported(fullMimeType, contentType)) {
|
|
51
51
|
return shaka.media.Transmuxer.convertCodecs(contentType, fullMimeType);
|
|
52
|
-
} else if (contentType == ContentType.AUDIO) {
|
|
52
|
+
} else if (mimeType != 'video/mp2t' && contentType == ContentType.AUDIO) {
|
|
53
53
|
// video/mp2t is the correct mime type for TS audio, so only replace the
|
|
54
54
|
// word "video" with "audio" for non-TS audio content.
|
|
55
55
|
return fullMimeType.replace('video', 'audio');
|
|
@@ -193,6 +193,17 @@ shaka.util.MimeUtils = class {
|
|
|
193
193
|
return value;
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Checks if the given MIME type is HLS MIME type.
|
|
198
|
+
*
|
|
199
|
+
* @param {string} mimeType
|
|
200
|
+
* @return {boolean}
|
|
201
|
+
*/
|
|
202
|
+
static isHlsType(mimeType) {
|
|
203
|
+
return mimeType === 'application/x-mpegurl' ||
|
|
204
|
+
mimeType === 'application/vnd.apple.mpegurl';
|
|
205
|
+
}
|
|
206
|
+
|
|
196
207
|
/**
|
|
197
208
|
* Get the base and profile of a codec string. Where [0] will be the codec
|
|
198
209
|
* base and [1] will be the profile.
|
package/lib/util/periods.js
CHANGED
|
@@ -671,11 +671,11 @@ shaka.util.PeriodCombiner = class {
|
|
|
671
671
|
// Also checks if the segmentIndex is still valid after the async
|
|
672
672
|
// operations, to make sure we stop if the active stream has changed.
|
|
673
673
|
if (outputStream.segmentIndex instanceof shaka.media.MetaSegmentIndex) {
|
|
674
|
-
for (let i =
|
|
674
|
+
for (let i = firstNewPeriodIndex; i < streams.length; i++) {
|
|
675
675
|
const match = streams[i];
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
676
|
+
goog.asserts.assert(match.segmentIndex,
|
|
677
|
+
'stream should have a segmentIndex.');
|
|
678
|
+
if (match.segmentIndex) {
|
|
679
679
|
outputStream.segmentIndex.appendSegmentIndex(match.segmentIndex);
|
|
680
680
|
}
|
|
681
681
|
}
|
|
@@ -728,7 +728,7 @@ shaka.util.PeriodCombiner = class {
|
|
|
728
728
|
// in advance. concat() will add them to the output's MetaSegmentIndex.
|
|
729
729
|
}
|
|
730
730
|
|
|
731
|
-
if (!outputStream.matchedStreams) {
|
|
731
|
+
if (!outputStream.matchedStreams || !outputStream.matchedStreams.length) {
|
|
732
732
|
// This is not a stream we can build output from, but it may become part
|
|
733
733
|
// of another output based on another period's stream.
|
|
734
734
|
return null;
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -712,26 +712,38 @@ shaka.util.StreamUtils = class {
|
|
|
712
712
|
}
|
|
713
713
|
|
|
714
714
|
if (audio) {
|
|
715
|
-
|
|
715
|
+
// See: https://github.com/shaka-project/shaka-player/issues/4659
|
|
716
|
+
if (info.audioRobustness != '') {
|
|
717
|
+
if (!keySystemConfig.audio) {
|
|
718
|
+
// KeySystemTrackConfiguration
|
|
719
|
+
keySystemConfig.audio = {
|
|
720
|
+
robustness: info.audioRobustness,
|
|
721
|
+
};
|
|
722
|
+
} else {
|
|
723
|
+
keySystemConfig.audio.robustness =
|
|
724
|
+
keySystemConfig.audio.robustness || info.audioRobustness;
|
|
725
|
+
}
|
|
726
|
+
} else if (!keySystemConfig.audio) {
|
|
716
727
|
// KeySystemTrackConfiguration
|
|
717
|
-
keySystemConfig.audio = {
|
|
718
|
-
robustness: info.audioRobustness,
|
|
719
|
-
};
|
|
720
|
-
} else {
|
|
721
|
-
keySystemConfig.audio.robustness =
|
|
722
|
-
keySystemConfig.audio.robustness || info.audioRobustness;
|
|
728
|
+
keySystemConfig.audio = {};
|
|
723
729
|
}
|
|
724
730
|
}
|
|
725
731
|
|
|
726
732
|
if (video) {
|
|
727
|
-
|
|
733
|
+
// See: https://github.com/shaka-project/shaka-player/issues/4659
|
|
734
|
+
if (info.videoRobustness != '') {
|
|
735
|
+
if (!keySystemConfig.video) {
|
|
736
|
+
// KeySystemTrackConfiguration
|
|
737
|
+
keySystemConfig.video = {
|
|
738
|
+
robustness: info.videoRobustness,
|
|
739
|
+
};
|
|
740
|
+
} else {
|
|
741
|
+
keySystemConfig.video.robustness =
|
|
742
|
+
keySystemConfig.video.robustness || info.videoRobustness;
|
|
743
|
+
}
|
|
744
|
+
} else if (!keySystemConfig.video) {
|
|
728
745
|
// KeySystemTrackConfiguration
|
|
729
|
-
keySystemConfig.video = {
|
|
730
|
-
robustness: info.videoRobustness,
|
|
731
|
-
};
|
|
732
|
-
} else {
|
|
733
|
-
keySystemConfig.video.robustness =
|
|
734
|
-
keySystemConfig.video.robustness || info.videoRobustness;
|
|
746
|
+
keySystemConfig.video = {};
|
|
735
747
|
}
|
|
736
748
|
}
|
|
737
749
|
}
|
|
@@ -818,7 +830,7 @@ shaka.util.StreamUtils = class {
|
|
|
818
830
|
const video = variant.video;
|
|
819
831
|
if (audio && currentVariant && currentVariant.audio) {
|
|
820
832
|
if (!StreamUtils.areStreamsCompatible_(audio, currentVariant.audio)) {
|
|
821
|
-
shaka.log.debug('
|
|
833
|
+
shaka.log.debug('Dropping variant - not compatible with active audio',
|
|
822
834
|
'active audio',
|
|
823
835
|
StreamUtils.getStreamSummaryString_(currentVariant.audio),
|
|
824
836
|
'variant.audio',
|
|
@@ -829,7 +841,7 @@ shaka.util.StreamUtils = class {
|
|
|
829
841
|
|
|
830
842
|
if (video && currentVariant && currentVariant.video) {
|
|
831
843
|
if (!StreamUtils.areStreamsCompatible_(video, currentVariant.video)) {
|
|
832
|
-
shaka.log.debug('
|
|
844
|
+
shaka.log.debug('Dropping variant - not compatible with active video',
|
|
833
845
|
'active video',
|
|
834
846
|
StreamUtils.getStreamSummaryString_(currentVariant.video),
|
|
835
847
|
'variant.video',
|
package/maintained-branches.md
CHANGED
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
We are currently maintaining the following branches of Shaka Player:
|
|
4
4
|
|
|
5
|
-
- v4.3 (latest)
|
|
5
|
+
- v4.3 (latest, also in use by the Cast Application Framework)
|
|
6
6
|
- v4.2 (previous)
|
|
7
|
-
-
|
|
8
|
-
- v3.2 (in use by the Cast Application Framework)
|
|
7
|
+
- No active LTS branches at this time
|
|
9
8
|
|
|
10
9
|
Other branches are no longer receiving bug fixes, and we recommend you upgrade
|
|
11
10
|
to a maintained branch. For details on upgrading, please see our
|
package/package.json
CHANGED
|
@@ -194,7 +194,8 @@ describe('DashParser Live', () => {
|
|
|
194
194
|
template, {updateTime: updateTime, contents: basicLines.join('\n')});
|
|
195
195
|
|
|
196
196
|
fakeNetEngine.setResponseText('dummy://foo', text);
|
|
197
|
-
|
|
197
|
+
const baseTime = new Date(2015, 11, 30);
|
|
198
|
+
Date.now = () => baseTime.getTime();
|
|
198
199
|
const manifest = await parser.start('dummy://foo', playerInterface);
|
|
199
200
|
|
|
200
201
|
expect(manifest).toBeTruthy();
|
|
@@ -211,7 +212,7 @@ describe('DashParser Live', () => {
|
|
|
211
212
|
// seconds long in all of these cases. So 11 seconds after the
|
|
212
213
|
// manifest was parsed, the first segment should have fallen out of
|
|
213
214
|
// the availability window.
|
|
214
|
-
Date.now = () => 11 * 1000;
|
|
215
|
+
Date.now = () => baseTime.getTime() + (11 * 1000);
|
|
215
216
|
await updateManifest();
|
|
216
217
|
// The first reference should have been evicted.
|
|
217
218
|
expect(stream.segmentIndex.find(0)).toBe(firstPosition + 1);
|
|
@@ -987,6 +987,118 @@ describe('HlsParser', () => {
|
|
|
987
987
|
await testHlsParser(master, media, manifest);
|
|
988
988
|
});
|
|
989
989
|
|
|
990
|
+
it('parses discontinuity tags', async () => {
|
|
991
|
+
const master = [
|
|
992
|
+
'#EXTM3U\n',
|
|
993
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=2000000,CODECS="avc1"\n',
|
|
994
|
+
'video\n',
|
|
995
|
+
].join('');
|
|
996
|
+
|
|
997
|
+
const media = [
|
|
998
|
+
'#EXTM3U\n',
|
|
999
|
+
'#EXT-X-VERSION:3\n',
|
|
1000
|
+
'#EXT-X-TARGETDURATION:5\n',
|
|
1001
|
+
'#EXT-X-MEDIA-SEQUENCE:0\n',
|
|
1002
|
+
'#EXTINF:3,\n',
|
|
1003
|
+
'clip0-video-0.ts\n',
|
|
1004
|
+
'#EXTINF:1,\n',
|
|
1005
|
+
'clip0-video-1.ts\n',
|
|
1006
|
+
'#EXT-X-DISCONTINUITY\n',
|
|
1007
|
+
'#EXTINF:2,\n',
|
|
1008
|
+
'clip1-video-1.ts\n',
|
|
1009
|
+
'#EXTINF:3,\n',
|
|
1010
|
+
'clip1-video-2.ts\n',
|
|
1011
|
+
'#EXT-X-DISCONTINUITY\n',
|
|
1012
|
+
'#EXTINF:1,\n',
|
|
1013
|
+
'media-clip2-video-0.ts\n',
|
|
1014
|
+
'#EXTINF:1,\n',
|
|
1015
|
+
'media-clip2-video-1.ts\n',
|
|
1016
|
+
'#EXT-X-DISCONTINUITY\n',
|
|
1017
|
+
'#EXTINF:4,\n',
|
|
1018
|
+
'media-clip3-video-1.ts\n',
|
|
1019
|
+
'#EXT-X-ENDLIST\n',
|
|
1020
|
+
].join('');
|
|
1021
|
+
|
|
1022
|
+
fakeNetEngine
|
|
1023
|
+
.setResponseText('test:/master', master)
|
|
1024
|
+
.setResponseText('test:/video', media);
|
|
1025
|
+
|
|
1026
|
+
const manifest = await parser.start('test:/master', playerInterface);
|
|
1027
|
+
await manifest.variants[0].video.createSegmentIndex();
|
|
1028
|
+
|
|
1029
|
+
const segmentIndex = manifest.variants[0].video.segmentIndex;
|
|
1030
|
+
const references = [];
|
|
1031
|
+
|
|
1032
|
+
for (let i = 0; i < 7; i++) {
|
|
1033
|
+
references.push(segmentIndex.get(i));
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
expect(references[0].discontinuitySequence).toBe(0);
|
|
1037
|
+
expect(references[1].discontinuitySequence).toBe(0);
|
|
1038
|
+
expect(references[2].discontinuitySequence).toBe(1);
|
|
1039
|
+
expect(references[3].discontinuitySequence).toBe(1);
|
|
1040
|
+
expect(references[4].discontinuitySequence).toBe(2);
|
|
1041
|
+
expect(references[5].discontinuitySequence).toBe(2);
|
|
1042
|
+
expect(references[6].discontinuitySequence).toBe(3);
|
|
1043
|
+
});
|
|
1044
|
+
|
|
1045
|
+
it('sets reference timetampOffset based on discontinuity start time',
|
|
1046
|
+
async () => {
|
|
1047
|
+
const master = [
|
|
1048
|
+
'#EXTM3U\n',
|
|
1049
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=2000000,CODECS="avc1"\n',
|
|
1050
|
+
'video\n',
|
|
1051
|
+
].join('');
|
|
1052
|
+
|
|
1053
|
+
const media = [
|
|
1054
|
+
'#EXTM3U\n',
|
|
1055
|
+
'#EXT-X-VERSION:3\n',
|
|
1056
|
+
'#EXT-X-TARGETDURATION:5\n',
|
|
1057
|
+
'#EXT-X-MEDIA-SEQUENCE:0\n',
|
|
1058
|
+
'#EXTINF:3,\n',
|
|
1059
|
+
'clip0-video-0.ts\n',
|
|
1060
|
+
'#EXTINF:1,\n',
|
|
1061
|
+
'clip0-video-1.ts\n',
|
|
1062
|
+
'#EXT-X-DISCONTINUITY\n',
|
|
1063
|
+
'#EXTINF:2,\n',
|
|
1064
|
+
'clip1-video-1.ts\n',
|
|
1065
|
+
'#EXTINF:3,\n',
|
|
1066
|
+
'clip1-video-2.ts\n',
|
|
1067
|
+
'#EXT-X-DISCONTINUITY\n',
|
|
1068
|
+
'#EXTINF:1,\n',
|
|
1069
|
+
'media-clip2-video-0.ts\n',
|
|
1070
|
+
'#EXTINF:1,\n',
|
|
1071
|
+
'media-clip2-video-1.ts\n',
|
|
1072
|
+
'#EXT-X-DISCONTINUITY\n',
|
|
1073
|
+
'#EXTINF:4,\n',
|
|
1074
|
+
'media-clip3-video-1.ts\n',
|
|
1075
|
+
'#EXT-X-ENDLIST\n',
|
|
1076
|
+
].join('');
|
|
1077
|
+
|
|
1078
|
+
fakeNetEngine
|
|
1079
|
+
.setResponseText('test:/master', master)
|
|
1080
|
+
.setResponseText('test:/video', media);
|
|
1081
|
+
|
|
1082
|
+
const manifest = await parser.start('test:/master', playerInterface);
|
|
1083
|
+
await manifest.variants[0].video.createSegmentIndex();
|
|
1084
|
+
|
|
1085
|
+
const segmentIndex = manifest.variants[0].video.segmentIndex;
|
|
1086
|
+
const references = [];
|
|
1087
|
+
|
|
1088
|
+
for (let i = 0; i < 7; i++) {
|
|
1089
|
+
references.push(segmentIndex.get(i));
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
expect(references[0].timestampOffset).toBe(0);
|
|
1093
|
+
expect(references[1].timestampOffset).toBe(0);
|
|
1094
|
+
expect(references[2].timestampOffset).toBe(4);
|
|
1095
|
+
expect(references[3].timestampOffset).toBe(4);
|
|
1096
|
+
expect(references[4].timestampOffset).toBe(9);
|
|
1097
|
+
expect(references[5].timestampOffset).toBe(9);
|
|
1098
|
+
expect(references[6].timestampOffset).toBe(11);
|
|
1099
|
+
},
|
|
1100
|
+
);
|
|
1101
|
+
|
|
990
1102
|
it('parses characteristics from audio tags', async () => {
|
|
991
1103
|
const master = [
|
|
992
1104
|
'#EXTM3U\n',
|
|
@@ -2132,6 +2244,50 @@ describe('HlsParser', () => {
|
|
|
2132
2244
|
expect(actual).toEqual(manifest);
|
|
2133
2245
|
});
|
|
2134
2246
|
|
|
2247
|
+
it('parses manifest with MP4+WEBVTT streams', async () => {
|
|
2248
|
+
const master = [
|
|
2249
|
+
'#EXTM3U\n',
|
|
2250
|
+
'#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="sub1",LANGUAGE="eng",',
|
|
2251
|
+
'CODECS="wvtt",URI="text"\n',
|
|
2252
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",',
|
|
2253
|
+
'RESOLUTION=960x540,FRAME-RATE=60,SUBTITLES="sub1"\n',
|
|
2254
|
+
'video\n',
|
|
2255
|
+
].join('');
|
|
2256
|
+
|
|
2257
|
+
const media = [
|
|
2258
|
+
'#EXTM3U\n',
|
|
2259
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
2260
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
2261
|
+
'#EXTINF:5,\n',
|
|
2262
|
+
'#EXT-X-BYTERANGE:121090@616\n',
|
|
2263
|
+
'main.mp4',
|
|
2264
|
+
].join('');
|
|
2265
|
+
|
|
2266
|
+
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
2267
|
+
manifest.anyTimeline();
|
|
2268
|
+
manifest.addPartialVariant((variant) => {
|
|
2269
|
+
variant.addPartialStream(ContentType.VIDEO);
|
|
2270
|
+
});
|
|
2271
|
+
manifest.addPartialTextStream((stream) => {
|
|
2272
|
+
stream.language = 'en';
|
|
2273
|
+
stream.mime('application/mp4', 'wvtt');
|
|
2274
|
+
});
|
|
2275
|
+
manifest.sequenceMode = true;
|
|
2276
|
+
});
|
|
2277
|
+
|
|
2278
|
+
fakeNetEngine
|
|
2279
|
+
.setResponseText('test:/master', master)
|
|
2280
|
+
.setResponseText('test:/audio', media)
|
|
2281
|
+
.setResponseText('test:/video', media)
|
|
2282
|
+
.setResponseText('test:/text', media)
|
|
2283
|
+
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
2284
|
+
.setResponseValue('test:/main.mp4', segmentData);
|
|
2285
|
+
|
|
2286
|
+
const actual = await parser.start('test:/master', playerInterface);
|
|
2287
|
+
await loadAllStreamsFor(actual);
|
|
2288
|
+
expect(actual).toEqual(manifest);
|
|
2289
|
+
});
|
|
2290
|
+
|
|
2135
2291
|
it('detects VTT streams by codec', async () => {
|
|
2136
2292
|
const master = [
|
|
2137
2293
|
'#EXTM3U\n',
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
describe('ContentWorkarounds', () => {
|
|
8
|
+
const encryptionBoxes = {
|
|
9
|
+
'encv': ['hev1', 'hvc1', 'avc1', 'avc3'],
|
|
10
|
+
'enca': ['ac-3', 'ec-3', 'mp4a'],
|
|
11
|
+
};
|
|
12
|
+
for (const encryptionBox of Object.keys(encryptionBoxes)) {
|
|
13
|
+
for (const box of encryptionBoxes[encryptionBox]) {
|
|
14
|
+
it(`adds ${encryptionBox} box for ${box}`, () => {
|
|
15
|
+
const boxType = [];
|
|
16
|
+
for (const char of box) {
|
|
17
|
+
boxType.push(char.charCodeAt(0));
|
|
18
|
+
}
|
|
19
|
+
const unencrypted = new Uint8Array([
|
|
20
|
+
0x00, 0x00, 0x00, 0x20, // size
|
|
21
|
+
0x73, 0x74, 0x73, 0x64, // stsd
|
|
22
|
+
0x01, // version
|
|
23
|
+
0x12, 0x34, 0x56, // flags
|
|
24
|
+
0x00, 0x00, 0x00, 0x01, // count
|
|
25
|
+
0x00, 0x00, 0x00, 0x10, // size
|
|
26
|
+
...boxType, // box type
|
|
27
|
+
0x01, // version
|
|
28
|
+
0x12, 0x34, 0x56, // flags
|
|
29
|
+
0x00, 0x11, 0x22, 0x33, // payload
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
const faked =
|
|
33
|
+
shaka.media.ContentWorkarounds.fakeEncryption(unencrypted);
|
|
34
|
+
const spy = jasmine.createSpy('boxCallback');
|
|
35
|
+
new shaka.util.Mp4Parser()
|
|
36
|
+
.fullBox('stsd', shaka.util.Mp4Parser.sampleDescription)
|
|
37
|
+
.box(encryptionBox, /** @type {!Function} */ (spy))
|
|
38
|
+
.parse(faked);
|
|
39
|
+
expect(spy).toHaveBeenCalled();
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
@@ -74,19 +74,6 @@ describe('DrmEngine', () => {
|
|
|
74
74
|
onEventSpy = jasmine.createSpy('onEvent');
|
|
75
75
|
|
|
76
76
|
networkingEngine = new shaka.net.NetworkingEngine();
|
|
77
|
-
networkingEngine.registerRequestFilter((type, request) => {
|
|
78
|
-
if (type != shaka.net.NetworkingEngine.RequestType.LICENSE) {
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
request.headers['X-AxDRM-Message'] = [
|
|
83
|
-
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lk',
|
|
84
|
-
'IjoiNjllNTQwODgtZTllMC00NTMwLThjMWEtMWViNmRjZDBkMTRlIiwibWVzc2FnZSI6e',
|
|
85
|
-
'yJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImtleXMiOlt7ImlkIjoiNmU1YTFkMj',
|
|
86
|
-
'YtMjc1Ny00N2Q3LTgwNDYtZWFhNWQxZDM0YjVhIn1dfX0.yF7PflOPv9qHnu3ZWJNZ12j',
|
|
87
|
-
'gkqTabmwXbDWk_47tLNE',
|
|
88
|
-
].join('');
|
|
89
|
-
});
|
|
90
77
|
|
|
91
78
|
const playerInterface = {
|
|
92
79
|
netEngine: networkingEngine,
|
|
@@ -99,22 +86,22 @@ describe('DrmEngine', () => {
|
|
|
99
86
|
drmEngine = new shaka.media.DrmEngine(playerInterface);
|
|
100
87
|
const config = shaka.util.PlayerConfiguration.createDefault().drm;
|
|
101
88
|
config.servers['com.widevine.alpha'] =
|
|
102
|
-
'https://
|
|
89
|
+
'https://cwip-shaka-proxy.appspot.com/specific_key?blodJidXR9eARuql0dNLWg=GX8m9XLIZNIzizrl0RTqnA';
|
|
103
90
|
config.servers['com.microsoft.playready'] =
|
|
104
|
-
'https://
|
|
91
|
+
'https://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(kid:6e5a1d26-2757-47d7-8046-eaa5d1d34b5a,contentkey:GX8m9XLIZNIzizrl0RTqnA==,sl:150)';
|
|
105
92
|
drmEngine.configure(config);
|
|
106
93
|
|
|
107
94
|
manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
108
95
|
manifest.addVariant(0, (variant) => {
|
|
109
96
|
variant.addVideo(1, (stream) => {
|
|
110
97
|
stream.encrypted = true;
|
|
111
|
-
stream.addDrmInfo('com.widevine.alpha');
|
|
112
98
|
stream.addDrmInfo('com.microsoft.playready');
|
|
99
|
+
stream.addDrmInfo('com.widevine.alpha');
|
|
113
100
|
});
|
|
114
101
|
variant.addAudio(2, (stream) => {
|
|
115
102
|
stream.encrypted = true;
|
|
116
|
-
stream.addDrmInfo('com.widevine.alpha');
|
|
117
103
|
stream.addDrmInfo('com.microsoft.playready');
|
|
104
|
+
stream.addDrmInfo('com.widevine.alpha');
|
|
118
105
|
});
|
|
119
106
|
});
|
|
120
107
|
});
|
|
@@ -3412,7 +3412,12 @@ describe('StreamingEngine', () => {
|
|
|
3412
3412
|
netEngine.request.and.callFake((requestType, request) => {
|
|
3413
3413
|
const buffer = new ArrayBuffer(0);
|
|
3414
3414
|
/** @type {shaka.extern.Response} */
|
|
3415
|
-
const response = {
|
|
3415
|
+
const response = {
|
|
3416
|
+
uri: request.uris[0],
|
|
3417
|
+
originalUri: request.uris[0],
|
|
3418
|
+
data: buffer,
|
|
3419
|
+
headers: {},
|
|
3420
|
+
};
|
|
3416
3421
|
return shaka.util.AbortableOperation.completed(response);
|
|
3417
3422
|
});
|
|
3418
3423
|
|
|
@@ -1226,6 +1226,11 @@ describe('NetworkingEngine', /** @suppress {accessControls} */ () => {
|
|
|
1226
1226
|
|
|
1227
1227
|
/** @return {shaka.extern.Response} */
|
|
1228
1228
|
function createResponse() {
|
|
1229
|
-
return {
|
|
1229
|
+
return {
|
|
1230
|
+
uri: '',
|
|
1231
|
+
originalUri: '',
|
|
1232
|
+
data: new ArrayBuffer(5),
|
|
1233
|
+
headers: {},
|
|
1234
|
+
};
|
|
1230
1235
|
}
|
|
1231
1236
|
}); // describe('NetworkingEngine')
|