shaka-player 4.2.5 → 4.3.1
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 +7 -0
- package/.github/workflows/sync-labels.yaml +1 -1
- package/.github/workflows/update-issues.yaml +1 -1
- package/AUTHORS +4 -0
- package/CHANGELOG.md +114 -74
- package/CONTRIBUTORS +4 -0
- package/README.md +14 -0
- package/conditional/dummy_cast_proxy.js +120 -0
- package/demo/common/assets.js +58 -0
- package/demo/common/message_ids.js +22 -1
- package/demo/config.js +89 -5
- package/demo/demo.less +7 -1
- package/demo/index.html +8 -1
- package/demo/locales/en.json +21 -1
- package/demo/locales/source.json +82 -2
- package/demo/main.js +57 -1
- package/demo/search.js +2 -0
- package/demo/visualizer.js +337 -0
- package/demo/visualizer_button.js +103 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +107 -88
- package/dist/demo.compiled.debug.map +4 -4
- package/dist/demo.compiled.js +107 -88
- package/dist/demo.compiled.map +4 -4
- package/dist/demo.css +1 -1
- package/dist/demo.css.map +1 -1
- package/dist/deps.js +21 -13
- package/dist/locales.js +31 -31
- package/dist/receiver.compiled.debug.js +75 -77
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +75 -77
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +181 -27
- package/dist/shaka-player.compiled.debug.d.ts +181 -27
- package/dist/shaka-player.compiled.debug.externs.js +169 -31
- package/dist/shaka-player.compiled.debug.js +510 -450
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +169 -31
- package/dist/shaka-player.compiled.js +912 -874
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +181 -27
- package/dist/shaka-player.ui.debug.d.ts +181 -27
- package/dist/shaka-player.ui.debug.externs.js +169 -31
- package/dist/shaka-player.ui.debug.js +533 -471
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +169 -31
- package/dist/shaka-player.ui.js +1073 -1036
- package/dist/shaka-player.ui.map +4 -4
- package/docs/design/lcevc-architecture.png +0 -0
- package/docs/design/lcevc-demo.png +0 -0
- package/docs/design/lcevc-integration.md +72 -0
- package/docs/tutorials/fairplay.md +7 -0
- package/docs/tutorials/faq.md +1 -1
- package/docs/tutorials/ui.md +7 -7
- package/docs/tutorials/upgrade.md +6 -0
- package/externs/ima.js +13 -1
- package/externs/lcevc.js +81 -0
- package/externs/mux.js +1 -42
- package/externs/shaka/ads.js +11 -1
- package/externs/shaka/manifest_parser.js +5 -1
- package/externs/shaka/mp4_parser.js +3 -0
- package/externs/shaka/player.js +178 -15
- package/lib/abr/simple_abr_manager.js +7 -0
- package/lib/ads/ad_manager.js +0 -8
- package/lib/ads/client_side_ad.js +15 -0
- package/lib/ads/client_side_ad_manager.js +21 -8
- package/lib/ads/server_side_ad.js +15 -0
- package/lib/ads/server_side_ad_manager.js +3 -3
- package/lib/cast/cast_utils.js +2 -0
- package/lib/cea/dummy_cea_parser.js +28 -0
- package/lib/cea/i_cea_parser.js +14 -2
- package/lib/cea/mp4_cea_parser.js +108 -5
- package/lib/config/auto_show_text.js +33 -0
- package/lib/dash/dash_parser.js +1 -1
- package/lib/hls/hls_parser.js +808 -384
- package/lib/lcevc/lcevc_dil.js +152 -0
- package/lib/media/closed_caption_parser.js +9 -6
- package/lib/media/drm_engine.js +14 -6
- package/lib/media/media_source_capabilities.js +36 -0
- package/lib/media/media_source_engine.js +113 -28
- package/lib/media/presentation_timeline.js +26 -11
- package/lib/media/segment_reference.js +49 -1
- package/lib/media/streaming_engine.js +142 -12
- package/lib/media/transmuxer.js +78 -21
- package/lib/offline/storage.js +1 -0
- package/lib/player.js +456 -77
- package/lib/polyfill/media_capabilities.js +9 -5
- package/lib/polyfill/patchedmediakeys_apple.js +63 -4
- package/lib/text/vtt_text_parser.js +35 -1
- package/lib/util/dom_utils.js +0 -1
- package/lib/util/error.js +17 -0
- package/lib/util/fake_event.js +2 -0
- package/lib/util/id3_utils.js +300 -0
- package/lib/util/mime_utils.js +3 -6
- package/lib/util/mp4_box_parsers.js +39 -5
- package/lib/util/mp4_parser.js +35 -0
- package/lib/util/player_configuration.js +23 -1
- package/lib/util/stream_utils.js +5 -3
- package/lib/util/ts_parser.js +499 -0
- package/maintained-branches.md +2 -2
- package/package.json +7 -4
- package/roadmap.md +5 -3
- package/test/ads/ad_manager_unit.js +182 -29
- package/test/cast/cast_utils_unit.js +3 -1
- package/test/dash/dash_parser_content_protection_unit.js +1 -0
- package/test/dash/dash_parser_live_unit.js +1 -0
- package/test/dash/dash_parser_manifest_unit.js +93 -1
- package/test/dash/dash_parser_segment_base_unit.js +1 -0
- package/test/dash/dash_parser_segment_list_unit.js +1 -0
- package/test/dash/dash_parser_segment_template_unit.js +1 -0
- package/test/demo/demo_unit.js +2 -1
- package/test/hls/hls_live_unit.js +253 -19
- package/test/hls/hls_parser_unit.js +631 -12
- package/test/media/closed_caption_parser_unit.js +2 -1
- package/test/media/drm_engine_integration.js +3 -1
- package/test/media/media_source_engine_integration.js +71 -6
- package/test/media/media_source_engine_unit.js +10 -5
- package/test/media/streaming_engine_integration.js +4 -1
- package/test/media/streaming_engine_unit.js +144 -1
- package/test/media/transmuxer_integration.js +21 -10
- package/test/player_integration.js +224 -82
- package/test/player_unit.js +5 -2
- package/test/polyfill/media_capabilities_unit.js +21 -23
- package/test/polyfill/patchedmediakeys_apple_unit.js +130 -0
- package/test/test/assets/id3-metadata.aac +0 -0
- package/test/test/assets/id3-metadata.ts +0 -0
- package/test/test/assets/thumbnails-sprites.vtt +10 -0
- package/test/test/assets/thumbnails.vtt +10 -0
- package/test/test/util/dash_parser_util.js +2 -0
- package/test/test/util/fake_ad.js +21 -0
- package/test/test/util/fake_media_source_engine.js +7 -0
- package/test/test/util/id3_generator.js +100 -0
- package/test/test/util/manifest_generator.js +3 -6
- package/test/test/util/simple_fakes.js +4 -0
- package/test/test/util/stream_generator.js +38 -0
- package/test/test/util/test_scheme.js +43 -14
- package/test/text/vtt_text_parser_unit.js +11 -0
- package/test/util/id3_utils_unit.js +116 -0
- package/test/util/ts_parser_unit.js +77 -0
- package/third_party/closure-uri/uri.js +1 -1
- package/ui/less/containers.less +7 -0
- package/ui/ui.js +43 -4
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
goog.provide('shaka.lcevc.Dil');
|
|
8
|
+
goog.require('shaka.log');
|
|
9
|
+
goog.require('shaka.util.IReleasable');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @summary
|
|
13
|
+
* lcevcDil - (MPEG-5 Part 2 LCEVC - Decoder Integration Layer) provides
|
|
14
|
+
* all the operations related to the enhancement and rendering
|
|
15
|
+
* of LCEVC enabled streams and on to a canvas.
|
|
16
|
+
* @implements {shaka.util.IReleasable}
|
|
17
|
+
* @export
|
|
18
|
+
*/
|
|
19
|
+
shaka.lcevc.Dil = class {
|
|
20
|
+
/**
|
|
21
|
+
* @param {HTMLVideoElement} media The video element that will be attached to
|
|
22
|
+
* LCEVC Dil for input.
|
|
23
|
+
* @param {HTMLCanvasElement} canvas The canvas element that will be attached
|
|
24
|
+
* to LCEVC Dil to render the enhanced frames.
|
|
25
|
+
* @param {shaka.extern.LcevcConfiguration} dilConfig The LCEVC DIL
|
|
26
|
+
* config object to initialize the LCEVC DIL.
|
|
27
|
+
*/
|
|
28
|
+
constructor(media, canvas, dilConfig) {
|
|
29
|
+
/** @private {?LcevcDil.LcevcDIL} */
|
|
30
|
+
this.dil_ = null;
|
|
31
|
+
|
|
32
|
+
/** @private {number} */
|
|
33
|
+
this.variantId_ = -1;
|
|
34
|
+
|
|
35
|
+
/** @private {HTMLVideoElement} */
|
|
36
|
+
this.media_ = media;
|
|
37
|
+
|
|
38
|
+
/** @private {HTMLCanvasElement} */
|
|
39
|
+
this.canvas_ = canvas;
|
|
40
|
+
|
|
41
|
+
/** @private {shaka.extern.LcevcConfiguration} */
|
|
42
|
+
this.dilConfig_ = dilConfig;
|
|
43
|
+
|
|
44
|
+
this.create_();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Append data to the LCEVC Dil.
|
|
49
|
+
* @param {BufferSource} data
|
|
50
|
+
*/
|
|
51
|
+
appendBuffer(data) {
|
|
52
|
+
if (this.dil_) {
|
|
53
|
+
this.dil_.appendBuffer(data, 'video', this.variantId_);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Hide the canvas specifically in the case of a DRM Content
|
|
59
|
+
*/
|
|
60
|
+
hideCanvas() {
|
|
61
|
+
if (this.dil_) {
|
|
62
|
+
this.canvas_.classList.add('shaka-hidden');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Create LCEVC Dil.
|
|
68
|
+
* @private
|
|
69
|
+
*/
|
|
70
|
+
create_() {
|
|
71
|
+
if (this.isSupported_() && !this.dil_) {
|
|
72
|
+
if (LcevcDil.SupportObject.webGLSupport(this.canvas_)) {
|
|
73
|
+
// Make sure the canvas is not hidden from a previous playback session.
|
|
74
|
+
this.canvas_.classList.remove('shaka-hidden');
|
|
75
|
+
this.dil_ = new LcevcDil.LcevcDil(
|
|
76
|
+
this.media_,
|
|
77
|
+
this.canvas_,
|
|
78
|
+
this.dilConfig_);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Close LCEVC Dil.
|
|
85
|
+
* @override
|
|
86
|
+
* @export
|
|
87
|
+
*/
|
|
88
|
+
release() {
|
|
89
|
+
if (this.dil_) {
|
|
90
|
+
this.dil_.close();
|
|
91
|
+
this.dil_ = null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Check if the LCEVC Dil lib is present and is supported by the browser.
|
|
97
|
+
* @return {boolean}
|
|
98
|
+
* @private
|
|
99
|
+
*/
|
|
100
|
+
isSupported_() {
|
|
101
|
+
if (typeof libDPIModule === 'undefined') {
|
|
102
|
+
shaka.log.alwaysWarn(
|
|
103
|
+
'Could not Find LCEVC Library dependencies on this page');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (typeof LcevcDil === 'undefined') {
|
|
107
|
+
shaka.log.alwaysWarn('Could not Find LCEVC Library on this page');
|
|
108
|
+
} else {
|
|
109
|
+
if (!LcevcDil.SupportObject.SupportStatus) {
|
|
110
|
+
shaka.log.alwaysWarn(LcevcDil.SupportObject.SupportError);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return typeof LcevcDil !== 'undefined' &&
|
|
115
|
+
typeof libDPIModule !== 'undefined' &&
|
|
116
|
+
this.canvas_ instanceof HTMLCanvasElement &&
|
|
117
|
+
LcevcDil.SupportObject.SupportStatus;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Update current active variant
|
|
122
|
+
* @param {shaka.extern.Track} track
|
|
123
|
+
*/
|
|
124
|
+
updateVariant(track) {
|
|
125
|
+
let containerFormat = shaka.lcevc.Dil.ContainerFormat.MPEG2_TS;
|
|
126
|
+
switch (track.mimeType) {
|
|
127
|
+
case 'video/webm': {
|
|
128
|
+
containerFormat = shaka.lcevc.Dil.ContainerFormat.WEBM;
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
case 'video/mp4': {
|
|
132
|
+
containerFormat = shaka.lcevc.Dil.ContainerFormat.MP4;
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (this.dil_) {
|
|
137
|
+
this.variantId_ = track.id;
|
|
138
|
+
this.dil_.setLevelSwitching(track.id, true);
|
|
139
|
+
this.dil_.setContainerFormat(containerFormat);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Container Formats.
|
|
146
|
+
* @const @enum {number}
|
|
147
|
+
*/
|
|
148
|
+
shaka.lcevc.Dil.ContainerFormat = {
|
|
149
|
+
MPEG2_TS: 0,
|
|
150
|
+
WEBM: 1,
|
|
151
|
+
MP4: 2,
|
|
152
|
+
};
|
|
@@ -8,6 +8,7 @@ goog.provide('shaka.media.ClosedCaptionParser');
|
|
|
8
8
|
goog.provide('shaka.media.IClosedCaptionParser');
|
|
9
9
|
|
|
10
10
|
goog.require('shaka.cea.CeaDecoder');
|
|
11
|
+
goog.require('shaka.cea.DummyCeaParser');
|
|
11
12
|
goog.require('shaka.cea.Mp4CeaParser');
|
|
12
13
|
goog.require('shaka.util.BufferUtils');
|
|
13
14
|
goog.requireType('shaka.cea.ICaptionDecoder');
|
|
@@ -54,12 +55,14 @@ shaka.media.IClosedCaptionParser = class {
|
|
|
54
55
|
*/
|
|
55
56
|
shaka.media.ClosedCaptionParser = class {
|
|
56
57
|
/** */
|
|
57
|
-
constructor() {
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
constructor(mimeType) {
|
|
59
|
+
/** @private {!shaka.cea.ICeaParser} */
|
|
60
|
+
this.ceaParser_ = new shaka.cea.DummyCeaParser();
|
|
61
|
+
|
|
62
|
+
if (mimeType.includes('video/mp4')) {
|
|
63
|
+
// MP4 Parser to extract closed caption packets from H.264 video.
|
|
64
|
+
this.ceaParser_ = new shaka.cea.Mp4CeaParser();
|
|
65
|
+
}
|
|
63
66
|
|
|
64
67
|
/**
|
|
65
68
|
* Decoder for decoding CEA-X08 data from closed caption packets.
|
package/lib/media/drm_engine.js
CHANGED
|
@@ -845,7 +845,7 @@ shaka.media.DrmEngine = class {
|
|
|
845
845
|
if (shaka.media.Transmuxer.isSupported(realMimeType)) {
|
|
846
846
|
// This will be handled by the Transmuxer, so use the MIME type that the
|
|
847
847
|
// Transmuxer will produce.
|
|
848
|
-
return shaka.media.Transmuxer.
|
|
848
|
+
return shaka.media.Transmuxer.convertCodecs(stream.type, realMimeType);
|
|
849
849
|
}
|
|
850
850
|
return realMimeType;
|
|
851
851
|
}
|
|
@@ -1113,13 +1113,21 @@ shaka.media.DrmEngine = class {
|
|
|
1113
1113
|
const keys = [];
|
|
1114
1114
|
const keyIds = [];
|
|
1115
1115
|
|
|
1116
|
-
clearKeys.forEach((
|
|
1117
|
-
|
|
1118
|
-
|
|
1116
|
+
clearKeys.forEach((key, keyId) => {
|
|
1117
|
+
let kid = keyId;
|
|
1118
|
+
if (kid.length != 22) {
|
|
1119
|
+
kid = Uint8ArrayUtils.toBase64(
|
|
1120
|
+
Uint8ArrayUtils.fromHex(keyId), false);
|
|
1121
|
+
}
|
|
1122
|
+
let k = key;
|
|
1123
|
+
if (k.length != 22) {
|
|
1124
|
+
k = Uint8ArrayUtils.toBase64(
|
|
1125
|
+
Uint8ArrayUtils.fromHex(key), false);
|
|
1126
|
+
}
|
|
1119
1127
|
const keyObj = {
|
|
1120
1128
|
kty: 'oct',
|
|
1121
|
-
kid:
|
|
1122
|
-
k:
|
|
1129
|
+
kid: kid,
|
|
1130
|
+
k: k,
|
|
1123
1131
|
};
|
|
1124
1132
|
|
|
1125
1133
|
keys.push(keyObj);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*! @license
|
|
2
|
+
* Shaka Player
|
|
3
|
+
* Copyright 2016 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
goog.provide('shaka.media.Capabilities');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @summary
|
|
11
|
+
* This is for capturing all media source capabilities on current platform.
|
|
12
|
+
* And this is for static check and can not be constructed.
|
|
13
|
+
*/
|
|
14
|
+
shaka.media.Capabilities = class {
|
|
15
|
+
/**
|
|
16
|
+
* Cache browser engine call to improve performance on some poor platforms
|
|
17
|
+
*
|
|
18
|
+
* @param {string} type
|
|
19
|
+
* @return {boolean}
|
|
20
|
+
*/
|
|
21
|
+
static isTypeSupported(type) {
|
|
22
|
+
const supportMap = shaka.media.Capabilities.MediaSourceTypeSupportMap;
|
|
23
|
+
if (supportMap.has(type)) {
|
|
24
|
+
return supportMap.get(type);
|
|
25
|
+
}
|
|
26
|
+
const currentSupport = MediaSource.isTypeSupported(type);
|
|
27
|
+
supportMap.set(type, currentSupport);
|
|
28
|
+
return currentSupport;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Public it for unit test, and developer could also check the support map.
|
|
34
|
+
* @type {!Map.<string, boolean>}
|
|
35
|
+
*/
|
|
36
|
+
shaka.media.Capabilities.MediaSourceTypeSupportMap = new Map();
|
|
@@ -8,21 +8,27 @@ goog.provide('shaka.media.MediaSourceEngine');
|
|
|
8
8
|
|
|
9
9
|
goog.require('goog.asserts');
|
|
10
10
|
goog.require('shaka.log');
|
|
11
|
+
goog.require('shaka.media.Capabilities');
|
|
11
12
|
goog.require('shaka.media.ContentWorkarounds');
|
|
13
|
+
goog.require('shaka.media.ClosedCaptionParser');
|
|
12
14
|
goog.require('shaka.media.IClosedCaptionParser');
|
|
13
15
|
goog.require('shaka.media.SegmentReference');
|
|
14
16
|
goog.require('shaka.media.TimeRangesUtils');
|
|
15
17
|
goog.require('shaka.media.Transmuxer');
|
|
16
18
|
goog.require('shaka.text.TextEngine');
|
|
19
|
+
goog.require('shaka.util.BufferUtils');
|
|
17
20
|
goog.require('shaka.util.Destroyer');
|
|
18
21
|
goog.require('shaka.util.Error');
|
|
19
22
|
goog.require('shaka.util.EventManager');
|
|
20
23
|
goog.require('shaka.util.Functional');
|
|
21
24
|
goog.require('shaka.util.IDestroyable');
|
|
25
|
+
goog.require('shaka.util.Id3Utils');
|
|
22
26
|
goog.require('shaka.util.ManifestParserUtils');
|
|
23
27
|
goog.require('shaka.util.MimeUtils');
|
|
24
28
|
goog.require('shaka.util.Platform');
|
|
25
29
|
goog.require('shaka.util.PublicPromise');
|
|
30
|
+
goog.require('shaka.util.TsParser');
|
|
31
|
+
goog.require('shaka.lcevc.Dil');
|
|
26
32
|
|
|
27
33
|
|
|
28
34
|
/**
|
|
@@ -38,21 +44,22 @@ shaka.media.MediaSourceEngine = class {
|
|
|
38
44
|
/**
|
|
39
45
|
* @param {HTMLMediaElement} video The video element, whose source is tied to
|
|
40
46
|
* MediaSource during the lifetime of the MediaSourceEngine.
|
|
41
|
-
* @param {!shaka.media.IClosedCaptionParser} closedCaptionParser
|
|
42
|
-
* The closed caption parser that should be used to parser closed captions
|
|
43
|
-
* from the video stream. MediaSourceEngine takes ownership of the parser.
|
|
44
|
-
* When MediaSourceEngine is destroyed, it will destroy the parser.
|
|
45
47
|
* @param {!shaka.extern.TextDisplayer} textDisplayer
|
|
46
48
|
* The text displayer that will be used with the text engine.
|
|
47
49
|
* MediaSourceEngine takes ownership of the displayer. When
|
|
48
50
|
* MediaSourceEngine is destroyed, it will destroy the displayer.
|
|
49
51
|
* @param {!function(!Array.<shaka.extern.ID3Metadata>, number, ?number)=}
|
|
50
52
|
* onMetadata
|
|
53
|
+
* @param {?shaka.lcevc.Dil} [lcevcDil] Optional - LCEVC Dil Object
|
|
54
|
+
*
|
|
51
55
|
*/
|
|
52
|
-
constructor(video,
|
|
56
|
+
constructor(video, textDisplayer, onMetadata, lcevcDil) {
|
|
53
57
|
/** @private {HTMLMediaElement} */
|
|
54
58
|
this.video_ = video;
|
|
55
59
|
|
|
60
|
+
/** @private {?shaka.extern.MediaSourceConfiguration} */
|
|
61
|
+
this.config_ = null;
|
|
62
|
+
|
|
56
63
|
/** @private {shaka.extern.TextDisplayer} */
|
|
57
64
|
this.textDisplayer_ = textDisplayer;
|
|
58
65
|
|
|
@@ -81,6 +88,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
81
88
|
number, ?number)} */
|
|
82
89
|
this.onMetadata_ = onMetadata || onMetadataNoOp;
|
|
83
90
|
|
|
91
|
+
/** @private {?shaka.lcevc.Dil} */
|
|
92
|
+
this.lcevcDil_ = lcevcDil || null;
|
|
93
|
+
|
|
84
94
|
/**
|
|
85
95
|
* @private {!Object.<string,
|
|
86
96
|
* !Array.<shaka.media.MediaSourceEngine.Operation>>}
|
|
@@ -93,8 +103,8 @@ shaka.media.MediaSourceEngine = class {
|
|
|
93
103
|
/** @private {!Object.<string, !shaka.media.Transmuxer>} */
|
|
94
104
|
this.transmuxers_ = {};
|
|
95
105
|
|
|
96
|
-
/** @private {shaka.media.IClosedCaptionParser} */
|
|
97
|
-
this.captionParser_ =
|
|
106
|
+
/** @private {?shaka.media.IClosedCaptionParser} */
|
|
107
|
+
this.captionParser_ = null;
|
|
98
108
|
|
|
99
109
|
/** @private {!shaka.util.PublicPromise} */
|
|
100
110
|
this.mediaSourceOpen_ = new shaka.util.PublicPromise();
|
|
@@ -166,7 +176,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
166
176
|
stream.mimeType, stream.codecs);
|
|
167
177
|
const extendedMimeType = shaka.util.MimeUtils.getExtendedType(stream);
|
|
168
178
|
return shaka.text.TextEngine.isTypeSupported(fullMimeType) ||
|
|
169
|
-
|
|
179
|
+
shaka.media.Capabilities.isTypeSupported(extendedMimeType) ||
|
|
170
180
|
shaka.media.Transmuxer.isSupported(fullMimeType, stream.type);
|
|
171
181
|
}
|
|
172
182
|
|
|
@@ -222,7 +232,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
222
232
|
if (shaka.text.TextEngine.isTypeSupported(type)) {
|
|
223
233
|
support[type] = true;
|
|
224
234
|
} else {
|
|
225
|
-
support[type] =
|
|
235
|
+
support[type] = shaka.media.Capabilities.isTypeSupported(type) ||
|
|
226
236
|
shaka.media.Transmuxer.isSupported(type);
|
|
227
237
|
}
|
|
228
238
|
} else {
|
|
@@ -291,6 +301,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
291
301
|
this.video_ = null;
|
|
292
302
|
}
|
|
293
303
|
|
|
304
|
+
this.config_ = null;
|
|
294
305
|
this.mediaSource_ = null;
|
|
295
306
|
this.textEngine_ = null;
|
|
296
307
|
this.textDisplayer_ = null;
|
|
@@ -305,6 +316,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
305
316
|
}
|
|
306
317
|
}
|
|
307
318
|
this.queues_ = {};
|
|
319
|
+
|
|
320
|
+
// This object is owned by Player
|
|
321
|
+
this.lcevcDil_ = null;
|
|
308
322
|
}
|
|
309
323
|
|
|
310
324
|
/**
|
|
@@ -325,15 +339,16 @@ shaka.media.MediaSourceEngine = class {
|
|
|
325
339
|
* shaka.extern.Stream>} streamsByType
|
|
326
340
|
* A map of content types to streams. All streams must be supported
|
|
327
341
|
* according to MediaSourceEngine.isStreamSupported.
|
|
328
|
-
* @param {boolean}
|
|
329
|
-
* If true, this will transmux TS content even if it is natively
|
|
342
|
+
* @param {boolean} forceTransmux
|
|
343
|
+
* If true, this will transmux AAC and TS content even if it is natively
|
|
344
|
+
* supported.
|
|
330
345
|
* @param {boolean=} sequenceMode
|
|
331
346
|
* If true, the media segments are appended to the SourceBuffer in strict
|
|
332
347
|
* sequence.
|
|
333
348
|
*
|
|
334
349
|
* @return {!Promise}
|
|
335
350
|
*/
|
|
336
|
-
async init(streamsByType,
|
|
351
|
+
async init(streamsByType, forceTransmux, sequenceMode=false) {
|
|
337
352
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
338
353
|
|
|
339
354
|
await this.mediaSourceOpen_;
|
|
@@ -351,14 +366,16 @@ shaka.media.MediaSourceEngine = class {
|
|
|
351
366
|
if (contentType == ContentType.TEXT) {
|
|
352
367
|
this.reinitText(mimeType, sequenceMode);
|
|
353
368
|
} else {
|
|
354
|
-
if ((
|
|
369
|
+
if ((forceTransmux ||
|
|
370
|
+
!shaka.media.Capabilities.isTypeSupported(mimeType)) &&
|
|
355
371
|
shaka.media.Transmuxer.isSupported(mimeType, contentType)) {
|
|
356
|
-
this.transmuxers_[contentType] =
|
|
372
|
+
this.transmuxers_[contentType] =
|
|
373
|
+
new shaka.media.Transmuxer(mimeType);
|
|
357
374
|
mimeType =
|
|
358
|
-
shaka.media.Transmuxer.
|
|
375
|
+
shaka.media.Transmuxer.convertCodecs(contentType, mimeType);
|
|
359
376
|
}
|
|
360
|
-
|
|
361
|
-
const sourceBuffer = this.mediaSource_.addSourceBuffer(
|
|
377
|
+
const type = mimeType + this.config_.sourceBufferExtraFeatures;
|
|
378
|
+
const sourceBuffer = this.mediaSource_.addSourceBuffer(type);
|
|
362
379
|
|
|
363
380
|
this.eventManager_.listen(
|
|
364
381
|
sourceBuffer, 'error',
|
|
@@ -374,6 +391,16 @@ shaka.media.MediaSourceEngine = class {
|
|
|
374
391
|
}
|
|
375
392
|
}
|
|
376
393
|
|
|
394
|
+
/**
|
|
395
|
+
* Called by the Player to provide an updated configuration any time it
|
|
396
|
+
* changes. Must be called at least once before init().
|
|
397
|
+
*
|
|
398
|
+
* @param {shaka.extern.MediaSourceConfiguration} config
|
|
399
|
+
*/
|
|
400
|
+
configure(config) {
|
|
401
|
+
this.config_ = config;
|
|
402
|
+
}
|
|
403
|
+
|
|
377
404
|
/**
|
|
378
405
|
* Reinitialize the TextEngine for a new text type.
|
|
379
406
|
* @param {string} mimeType
|
|
@@ -509,6 +536,17 @@ shaka.media.MediaSourceEngine = class {
|
|
|
509
536
|
}
|
|
510
537
|
}
|
|
511
538
|
|
|
539
|
+
/**
|
|
540
|
+
* Create a new closed caption parser. This will ONLY be replaced by tests as
|
|
541
|
+
* a way to inject fake closed caption parser instances.
|
|
542
|
+
*
|
|
543
|
+
* @param {string} mimeType
|
|
544
|
+
* @return {!shaka.media.IClosedCaptionParser}
|
|
545
|
+
*/
|
|
546
|
+
getCaptionParser(mimeType) {
|
|
547
|
+
return new shaka.media.ClosedCaptionParser(mimeType);
|
|
548
|
+
}
|
|
549
|
+
|
|
512
550
|
/**
|
|
513
551
|
* Enqueue an operation to append data to the SourceBuffer.
|
|
514
552
|
* Start and end times are needed for TextEngine, but not for MediaSource.
|
|
@@ -544,6 +582,40 @@ shaka.media.MediaSourceEngine = class {
|
|
|
544
582
|
return;
|
|
545
583
|
}
|
|
546
584
|
|
|
585
|
+
const uint8ArrayData = shaka.util.BufferUtils.toUint8(data);
|
|
586
|
+
let mimeType = this.sourceBufferTypes_[contentType];
|
|
587
|
+
if (this.transmuxers_[contentType]) {
|
|
588
|
+
mimeType = this.transmuxers_[contentType].getOrginalMimeType();
|
|
589
|
+
}
|
|
590
|
+
if (shaka.util.TsParser.probe(uint8ArrayData)) {
|
|
591
|
+
const tsParser = new shaka.util.TsParser().parse(uint8ArrayData);
|
|
592
|
+
// The SourceBuffer timestampOffset may or may not be set yet, so this is
|
|
593
|
+
// the timestamp offset that would eventually compute for this segment
|
|
594
|
+
// either way.
|
|
595
|
+
const timestampOffset =
|
|
596
|
+
reference.startTime - (tsParser.getStartTime()[contentType] || 0);
|
|
597
|
+
const metadata = tsParser.getMetadata();
|
|
598
|
+
if (metadata.length) {
|
|
599
|
+
this.onMetadata_(metadata, timestampOffset,
|
|
600
|
+
reference ? reference.endTime : null);
|
|
601
|
+
}
|
|
602
|
+
} else {
|
|
603
|
+
if (shaka.media.MediaSourceEngine.RAW_FORMATS.includes(mimeType)) {
|
|
604
|
+
const frames = shaka.util.Id3Utils.getID3Frames(uint8ArrayData);
|
|
605
|
+
if (frames.length && reference) {
|
|
606
|
+
/** @private {shaka.extern.ID3Metadata} */
|
|
607
|
+
const metadata = {
|
|
608
|
+
cueTime: reference.startTime,
|
|
609
|
+
data: uint8ArrayData,
|
|
610
|
+
frames: frames,
|
|
611
|
+
dts: reference.startTime,
|
|
612
|
+
pts: reference.startTime,
|
|
613
|
+
};
|
|
614
|
+
this.onMetadata_([metadata], /* offset= */ 0, reference.endTime);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
547
619
|
if (this.transmuxers_[contentType]) {
|
|
548
620
|
// When seeked we should reset the transmuxer captionstreams
|
|
549
621
|
// so it does not ignores the captions from previous segments
|
|
@@ -558,15 +630,6 @@ shaka.media.MediaSourceEngine = class {
|
|
|
558
630
|
if (!this.textEngine_) {
|
|
559
631
|
this.reinitText('text/vtt', this.sequenceMode_);
|
|
560
632
|
}
|
|
561
|
-
|
|
562
|
-
if (transmuxedData.metadata) {
|
|
563
|
-
const timestampOffset =
|
|
564
|
-
this.sourceBuffers_[contentType].timestampOffset;
|
|
565
|
-
this.onMetadata_(
|
|
566
|
-
transmuxedData.metadata,
|
|
567
|
-
timestampOffset,
|
|
568
|
-
reference ? reference.endTime : null);
|
|
569
|
-
}
|
|
570
633
|
// This doesn't work for native TS support (ex. Edge/Chromecast),
|
|
571
634
|
// since no transmuxing is needed for native TS.
|
|
572
635
|
if (transmuxedData.captions && transmuxedData.captions.length) {
|
|
@@ -582,10 +645,13 @@ shaka.media.MediaSourceEngine = class {
|
|
|
582
645
|
}
|
|
583
646
|
|
|
584
647
|
data = transmuxedData.data;
|
|
585
|
-
} else if (hasClosedCaptions) {
|
|
648
|
+
} else if (hasClosedCaptions && contentType == ContentType.VIDEO) {
|
|
586
649
|
if (!this.textEngine_) {
|
|
587
650
|
this.reinitText('text/vtt', this.sequenceMode_);
|
|
588
651
|
}
|
|
652
|
+
if (!this.captionParser_) {
|
|
653
|
+
this.captionParser_ = this.getCaptionParser(mimeType);
|
|
654
|
+
}
|
|
589
655
|
// If it is the init segment for closed captions, initialize the closed
|
|
590
656
|
// caption parser.
|
|
591
657
|
if (!reference) {
|
|
@@ -779,7 +845,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
779
845
|
* Fully reset the state of the caption parser owned by MediaSourceEngine.
|
|
780
846
|
*/
|
|
781
847
|
resetCaptionParser() {
|
|
782
|
-
this.captionParser_
|
|
848
|
+
if (this.captionParser_) {
|
|
849
|
+
this.captionParser_.reset();
|
|
850
|
+
}
|
|
783
851
|
}
|
|
784
852
|
|
|
785
853
|
/**
|
|
@@ -918,6 +986,15 @@ shaka.media.MediaSourceEngine = class {
|
|
|
918
986
|
* @private
|
|
919
987
|
*/
|
|
920
988
|
append_(contentType, data) {
|
|
989
|
+
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
990
|
+
|
|
991
|
+
// Append only video data to the LCEVC Dil.
|
|
992
|
+
if (contentType == ContentType.VIDEO && this.lcevcDil_) {
|
|
993
|
+
// Append video buffers to the LCEVC Dil for parsing and storing
|
|
994
|
+
// of LCEVC data.
|
|
995
|
+
this.lcevcDil_.appendBuffer(data);
|
|
996
|
+
}
|
|
997
|
+
|
|
921
998
|
// This will trigger an 'updateend' event.
|
|
922
999
|
this.sourceBuffers_[contentType].appendBuffer(data);
|
|
923
1000
|
}
|
|
@@ -1283,6 +1360,14 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1283
1360
|
|
|
1284
1361
|
return segment;
|
|
1285
1362
|
}
|
|
1363
|
+
|
|
1364
|
+
/**
|
|
1365
|
+
* Update LCEVC DIL object when ready for LCEVC Decodes
|
|
1366
|
+
* @param {?shaka.lcevc.Dil} lcevcDil
|
|
1367
|
+
*/
|
|
1368
|
+
updateLcevcDil(lcevcDil) {
|
|
1369
|
+
this.lcevcDil_ = lcevcDil;
|
|
1370
|
+
}
|
|
1286
1371
|
};
|
|
1287
1372
|
|
|
1288
1373
|
|
|
@@ -118,6 +118,20 @@ shaka.media.PresentationTimeline = class {
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Sets the presentation's start time.
|
|
123
|
+
*
|
|
124
|
+
* @param {number} presentationStartTime The wall-clock time, in seconds,
|
|
125
|
+
* when the presentation started or will start. Only required for live.
|
|
126
|
+
* @export
|
|
127
|
+
*/
|
|
128
|
+
setPresentationStartTime(presentationStartTime) {
|
|
129
|
+
goog.asserts.assert(presentationStartTime >= 0,
|
|
130
|
+
'presentationStartTime must be >= 0');
|
|
131
|
+
this.presentationStartTime_ = presentationStartTime;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
|
|
121
135
|
/**
|
|
122
136
|
* Sets the presentation's duration.
|
|
123
137
|
*
|
|
@@ -207,10 +221,10 @@ shaka.media.PresentationTimeline = class {
|
|
|
207
221
|
|
|
208
222
|
|
|
209
223
|
/**
|
|
210
|
-
* Gives PresentationTimeline
|
|
224
|
+
* Gives PresentationTimeline an array of segments so it can size and position
|
|
211
225
|
* the segment availability window, and account for missing segment
|
|
212
|
-
* information.
|
|
213
|
-
*
|
|
226
|
+
* information. These segments do not necessarily need to all be from the
|
|
227
|
+
* same stream.
|
|
214
228
|
*
|
|
215
229
|
* @param {!Array.<!shaka.media.SegmentReference>} references
|
|
216
230
|
* @export
|
|
@@ -220,15 +234,16 @@ shaka.media.PresentationTimeline = class {
|
|
|
220
234
|
return;
|
|
221
235
|
}
|
|
222
236
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
237
|
+
let firstReferenceStartTime = references[0].startTime;
|
|
238
|
+
let lastReferenceEndTime = references[0].endTime;
|
|
239
|
+
for (const reference of references) {
|
|
240
|
+
firstReferenceStartTime = Math.min(
|
|
241
|
+
firstReferenceStartTime, reference.startTime);
|
|
242
|
+
lastReferenceEndTime = Math.max(lastReferenceEndTime, reference.endTime);
|
|
243
|
+
this.maxSegmentDuration_ = Math.max(
|
|
244
|
+
this.maxSegmentDuration_, reference.endTime - reference.startTime);
|
|
245
|
+
}
|
|
226
246
|
this.notifyMinSegmentStartTime(firstReferenceStartTime);
|
|
227
|
-
|
|
228
|
-
this.maxSegmentDuration_ = references.reduce(
|
|
229
|
-
(max, r) => { return Math.max(max, r.endTime - r.startTime); },
|
|
230
|
-
this.maxSegmentDuration_);
|
|
231
|
-
|
|
232
247
|
this.maxSegmentEndTime_ =
|
|
233
248
|
Math.max(this.maxSegmentEndTime_, lastReferenceEndTime);
|
|
234
249
|
|
|
@@ -28,8 +28,9 @@ shaka.media.InitSegmentReference = class {
|
|
|
28
28
|
* segment extends to the end of the resource.
|
|
29
29
|
* @param {null|shaka.extern.MediaQualityInfo=} mediaQuality Information about
|
|
30
30
|
* the quality of the media associated with this init segment.
|
|
31
|
+
* @param {number=} timescale
|
|
31
32
|
*/
|
|
32
|
-
constructor(uris, startByte, endByte, mediaQuality = null) {
|
|
33
|
+
constructor(uris, startByte, endByte, mediaQuality = null, timescale) {
|
|
33
34
|
/** @type {function():!Array.<string>} */
|
|
34
35
|
this.getUris = uris;
|
|
35
36
|
|
|
@@ -41,6 +42,9 @@ shaka.media.InitSegmentReference = class {
|
|
|
41
42
|
|
|
42
43
|
/** @const {shaka.extern.MediaQualityInfo|null} */
|
|
43
44
|
this.mediaQuality = mediaQuality;
|
|
45
|
+
|
|
46
|
+
/** @type {number|undefined} */
|
|
47
|
+
this.timescale = timescale;
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
/**
|
|
@@ -239,6 +243,9 @@ shaka.media.SegmentReference = class {
|
|
|
239
243
|
|
|
240
244
|
/** @type {?shaka.extern.HlsAes128Key} */
|
|
241
245
|
this.hlsAes128Key = hlsAes128Key;
|
|
246
|
+
|
|
247
|
+
/** @type {?shaka.media.SegmentReference.ThumbnailSprite} */
|
|
248
|
+
this.thumbnailSprite = null;
|
|
242
249
|
}
|
|
243
250
|
|
|
244
251
|
/**
|
|
@@ -353,6 +360,26 @@ shaka.media.SegmentReference = class {
|
|
|
353
360
|
markAsUnavailable() {
|
|
354
361
|
this.status = shaka.media.SegmentReference.Status.UNAVAILABLE;
|
|
355
362
|
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Set the segment's thumbnail sprite.
|
|
366
|
+
*
|
|
367
|
+
* @param {shaka.media.SegmentReference.ThumbnailSprite} thumbnailSprite
|
|
368
|
+
* @export
|
|
369
|
+
*/
|
|
370
|
+
setThumbnailSprite(thumbnailSprite) {
|
|
371
|
+
this.thumbnailSprite = thumbnailSprite;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Returns the segment's thumbnail sprite.
|
|
376
|
+
*
|
|
377
|
+
* @return {?shaka.media.SegmentReference.ThumbnailSprite}
|
|
378
|
+
* @export
|
|
379
|
+
*/
|
|
380
|
+
getThumbnailSprite() {
|
|
381
|
+
return this.thumbnailSprite;
|
|
382
|
+
}
|
|
356
383
|
};
|
|
357
384
|
|
|
358
385
|
|
|
@@ -376,3 +403,24 @@ shaka.media.SegmentReference.Status = {
|
|
|
376
403
|
* @typedef {shaka.media.InitSegmentReference|shaka.media.SegmentReference}
|
|
377
404
|
*/
|
|
378
405
|
shaka.media.AnySegmentReference;
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* @typedef {{
|
|
410
|
+
* height: number,
|
|
411
|
+
* positionX: number,
|
|
412
|
+
* positionY: number,
|
|
413
|
+
* width: number
|
|
414
|
+
* }}
|
|
415
|
+
*
|
|
416
|
+
* @property {number} height
|
|
417
|
+
* The thumbnail height in px.
|
|
418
|
+
* @property {number} positionX
|
|
419
|
+
* The thumbnail left position in px.
|
|
420
|
+
* @property {number} positionY
|
|
421
|
+
* The thumbnail top position in px.
|
|
422
|
+
* @property {number} width
|
|
423
|
+
* The thumbnail width in px.
|
|
424
|
+
* @export
|
|
425
|
+
*/
|
|
426
|
+
shaka.media.SegmentReference.ThumbnailSprite;
|