shaka-player 4.7.10 → 4.7.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -4
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/deps.js +4 -5
- package/dist/locales.js +31 -31
- package/dist/shaka-player.compiled.d.ts +12 -10
- package/dist/shaka-player.compiled.debug.d.ts +12 -10
- package/dist/shaka-player.compiled.debug.externs.js +78 -64
- package/dist/shaka-player.compiled.debug.js +190 -183
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +78 -64
- package/dist/shaka-player.compiled.js +1122 -1115
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +12 -10
- package/dist/shaka-player.ui.debug.d.ts +12 -10
- package/dist/shaka-player.ui.debug.externs.js +78 -64
- package/dist/shaka-player.ui.debug.js +200 -193
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +78 -64
- package/dist/shaka-player.ui.js +1250 -1243
- package/dist/shaka-player.ui.map +4 -4
- package/externs/shaka/player.js +32 -19
- package/lib/abr/simple_abr_manager.js +21 -26
- package/lib/ads/ad_manager.js +1 -1
- package/lib/cast/cast_proxy.js +1 -3
- package/lib/cast/cast_sender.js +8 -11
- package/lib/cea/cea608_memory.js +1 -1
- package/lib/cea/ts_cea_parser.js +10 -1
- package/lib/dash/dash_parser.js +3 -0
- package/lib/deprecate/deprecate.js +1 -1
- package/lib/hls/hls_parser.js +40 -19
- package/lib/media/drm_engine.js +6 -3
- package/lib/media/manifest_parser.js +3 -2
- package/lib/media/media_source_engine.js +25 -12
- package/lib/media/presentation_timeline.js +23 -0
- package/lib/media/segment_utils.js +10 -1
- package/lib/player.js +19 -6
- package/lib/polyfill/media_capabilities.js +20 -1
- package/lib/polyfill/mediasource.js +35 -43
- package/lib/text/vtt_text_parser.js +53 -52
- package/lib/transmuxer/h264.js +3 -3
- package/lib/transmuxer/h265.js +3 -3
- package/lib/transmuxer/ts_transmuxer.js +42 -3
- package/lib/util/error.js +1 -0
- package/lib/util/manifest_parser_utils.js +1 -0
- package/lib/util/mp4_parser.js +57 -0
- package/lib/util/platform.js +4 -0
- package/lib/util/ts_parser.js +101 -12
- package/package.json +2 -2
- package/ui/less/containers.less +1 -0
- package/lib/polyfill/storage_estimate.js +0 -57
package/lib/player.js
CHANGED
|
@@ -742,7 +742,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
742
742
|
// player having been initialized.
|
|
743
743
|
if (mediaElement) {
|
|
744
744
|
shaka.Deprecate.deprecateFeature(5,
|
|
745
|
-
'Player',
|
|
745
|
+
'Player w/ mediaElement',
|
|
746
746
|
'Please migrate from initializing Player with a mediaElement; ' +
|
|
747
747
|
'use the attach method instead.');
|
|
748
748
|
this.attach(mediaElement, /* initializeMediaSource= */ true);
|
|
@@ -1858,19 +1858,19 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1858
1858
|
this.abrManager_ = abrFactory();
|
|
1859
1859
|
if (typeof this.abrManager_.setMediaElement != 'function') {
|
|
1860
1860
|
shaka.Deprecate.deprecateFeature(5,
|
|
1861
|
-
'AbrManager',
|
|
1861
|
+
'AbrManager w/o setMediaElement',
|
|
1862
1862
|
'Please use an AbrManager with setMediaElement function.');
|
|
1863
1863
|
this.abrManager_.setMediaElement = () => {};
|
|
1864
1864
|
}
|
|
1865
1865
|
if (typeof this.abrManager_.setCmsdManager != 'function') {
|
|
1866
1866
|
shaka.Deprecate.deprecateFeature(5,
|
|
1867
|
-
'AbrManager',
|
|
1867
|
+
'AbrManager w/o setCmsdManager',
|
|
1868
1868
|
'Please use an AbrManager with setCmsdManager function.');
|
|
1869
1869
|
this.abrManager_.setCmsdManager = () => {};
|
|
1870
1870
|
}
|
|
1871
1871
|
if (typeof this.abrManager_.trySuggestStreams != 'function') {
|
|
1872
1872
|
shaka.Deprecate.deprecateFeature(5,
|
|
1873
|
-
'AbrManager',
|
|
1873
|
+
'AbrManager w/o trySuggestStreams',
|
|
1874
1874
|
'Please use an AbrManager with trySuggestStreams function.');
|
|
1875
1875
|
this.abrManager_.trySuggestStreams = () => {};
|
|
1876
1876
|
}
|
|
@@ -4494,7 +4494,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
4494
4494
|
|
|
4495
4495
|
if (this.manifest_) {
|
|
4496
4496
|
const timeline = this.manifest_.presentationTimeline;
|
|
4497
|
-
const startTime = timeline.
|
|
4497
|
+
const startTime = timeline.getInitialProgramDateTime() ||
|
|
4498
|
+
timeline.getPresentationStartTime();
|
|
4498
4499
|
return new Date(/* ms= */ (startTime + presentationTime) * 1000);
|
|
4499
4500
|
} else if (this.video_ && this.video_.getStartDate) {
|
|
4500
4501
|
// Apple's native HLS gives us getStartDate(), which is only available if
|
|
@@ -6099,6 +6100,18 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
6099
6100
|
// change.
|
|
6100
6101
|
if (this.playhead_) {
|
|
6101
6102
|
this.playhead_.notifyOfBufferingChange();
|
|
6103
|
+
// Skip the initial buffer gap
|
|
6104
|
+
const startTime = this.mediaSourceEngine_.bufferStart(contentType);
|
|
6105
|
+
if (
|
|
6106
|
+
!this.isLive() &&
|
|
6107
|
+
// If not paused then GapJumpingController will handle this gap.
|
|
6108
|
+
this.video_.paused &&
|
|
6109
|
+
startTime != null &&
|
|
6110
|
+
startTime > 0 &&
|
|
6111
|
+
this.playhead_.getTime() < startTime
|
|
6112
|
+
) {
|
|
6113
|
+
this.playhead_.setStartTime(startTime);
|
|
6114
|
+
}
|
|
6102
6115
|
}
|
|
6103
6116
|
this.pollBufferState_();
|
|
6104
6117
|
|
|
@@ -6934,7 +6947,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6934
6947
|
* @export
|
|
6935
6948
|
*/
|
|
6936
6949
|
// eslint-disable-next-line no-useless-concat
|
|
6937
|
-
shaka.Player.version = 'v4.7.
|
|
6950
|
+
shaka.Player.version = 'v4.7.12' + '-uncompiled'; // x-release-please-version
|
|
6938
6951
|
|
|
6939
6952
|
// Initialize the deprecation system using the version string we just set
|
|
6940
6953
|
// on the player.
|
|
@@ -300,7 +300,17 @@ shaka.polyfill.MediaCapabilities = class {
|
|
|
300
300
|
// this query is specifically for HDR.
|
|
301
301
|
displayType += '; eotf=smpte2084';
|
|
302
302
|
}
|
|
303
|
-
|
|
303
|
+
let result = false;
|
|
304
|
+
if (displayType in shaka.polyfill.MediaCapabilities
|
|
305
|
+
.memoizedCanDisplayTypeRequests_) {
|
|
306
|
+
result = shaka.polyfill.MediaCapabilities
|
|
307
|
+
.memoizedCanDisplayTypeRequests_[displayType];
|
|
308
|
+
} else {
|
|
309
|
+
result = cast.__platform__.canDisplayType(displayType);
|
|
310
|
+
shaka.polyfill.MediaCapabilities
|
|
311
|
+
.memoizedCanDisplayTypeRequests_[displayType] = result;
|
|
312
|
+
}
|
|
313
|
+
return result;
|
|
304
314
|
}
|
|
305
315
|
|
|
306
316
|
/**
|
|
@@ -337,6 +347,15 @@ shaka.polyfill.MediaCapabilities.originalMcap = null;
|
|
|
337
347
|
*/
|
|
338
348
|
shaka.polyfill.MediaCapabilities.memoizedMediaKeySystemAccessRequests_ = {};
|
|
339
349
|
|
|
350
|
+
/**
|
|
351
|
+
* A cache that stores the canDisplayType result of calling
|
|
352
|
+
* `cast.__platform__.canDisplayType`.
|
|
353
|
+
*
|
|
354
|
+
* @type {(Object<(!string), (!boolean)>)}
|
|
355
|
+
* @export
|
|
356
|
+
*/
|
|
357
|
+
shaka.polyfill.MediaCapabilities.memoizedCanDisplayTypeRequests_ = {};
|
|
358
|
+
|
|
340
359
|
// Install at a lower priority than MediaSource polyfill, so that we have
|
|
341
360
|
// MediaSource available first.
|
|
342
361
|
shaka.polyfill.register(shaka.polyfill.MediaCapabilities.install, -1);
|
|
@@ -30,13 +30,8 @@ shaka.polyfill.MediaSource = class {
|
|
|
30
30
|
// platform detection tricks to decide which patches to install.
|
|
31
31
|
const safariVersion = shaka.util.Platform.safariVersion();
|
|
32
32
|
|
|
33
|
-
if (!window.MediaSource) {
|
|
33
|
+
if (!window.MediaSource && !window.ManagedMediaSource) {
|
|
34
34
|
shaka.log.info('No MSE implementation available.');
|
|
35
|
-
} else if (window.cast && cast.__platform__ &&
|
|
36
|
-
cast.__platform__.canDisplayType) {
|
|
37
|
-
shaka.log.info('Patching Chromecast MSE bugs.');
|
|
38
|
-
// Chromecast cannot make accurate determinations via isTypeSupported.
|
|
39
|
-
shaka.polyfill.MediaSource.patchCastIsTypeSupported_();
|
|
40
35
|
} else if (safariVersion) {
|
|
41
36
|
// NOTE: shaka.Player.isBrowserSupported() has its own restrictions on
|
|
42
37
|
// Safari version.
|
|
@@ -72,11 +67,6 @@ shaka.polyfill.MediaSource = class {
|
|
|
72
67
|
// Bug filed: https://bugs.webkit.org/show_bug.cgi?id=165342
|
|
73
68
|
shaka.polyfill.MediaSource.stubAbort_();
|
|
74
69
|
}
|
|
75
|
-
} else if (shaka.util.Platform.isEdge()) {
|
|
76
|
-
shaka.log.info('Rejecting TS container.');
|
|
77
|
-
// TS content is broken on Edge in general.
|
|
78
|
-
// See https://github.com/shaka-project/shaka-player/issues/4955
|
|
79
|
-
shaka.polyfill.MediaSource.rejectContainer_('mp2t');
|
|
80
70
|
} else if (shaka.util.Platform.isTizen2() ||
|
|
81
71
|
shaka.util.Platform.isTizen3() ||
|
|
82
72
|
shaka.util.Platform.isTizen4()) {
|
|
@@ -89,6 +79,14 @@ shaka.polyfill.MediaSource = class {
|
|
|
89
79
|
shaka.log.info('Using native MSE as-is.');
|
|
90
80
|
}
|
|
91
81
|
|
|
82
|
+
if (window.MediaSource || window.ManagedMediaSource) {
|
|
83
|
+
// TS content is broken on all browsers in general.
|
|
84
|
+
// See https://github.com/shaka-project/shaka-player/issues/4955
|
|
85
|
+
// See https://github.com/shaka-project/shaka-player/issues/5278
|
|
86
|
+
// See https://github.com/shaka-project/shaka-player/issues/6334
|
|
87
|
+
shaka.polyfill.MediaSource.rejectContainer_('mp2t');
|
|
88
|
+
}
|
|
89
|
+
|
|
92
90
|
if (window.MediaSource &&
|
|
93
91
|
MediaSource.isTypeSupported('video/webm; codecs="vp9"') &&
|
|
94
92
|
!MediaSource.isTypeSupported('video/webm; codecs="vp09.00.10.08"')) {
|
|
@@ -157,12 +155,25 @@ shaka.polyfill.MediaSource = class {
|
|
|
157
155
|
* @private
|
|
158
156
|
*/
|
|
159
157
|
static rejectContainer_(container) {
|
|
160
|
-
const isTypeSupported =
|
|
158
|
+
const isTypeSupported =
|
|
159
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
160
|
+
MediaSource.isTypeSupported.bind(MediaSource);
|
|
161
161
|
|
|
162
162
|
MediaSource.isTypeSupported = (mimeType) => {
|
|
163
163
|
const actualContainer = shaka.util.MimeUtils.getContainerType(mimeType);
|
|
164
164
|
return actualContainer != container && isTypeSupported(mimeType);
|
|
165
165
|
};
|
|
166
|
+
|
|
167
|
+
if (window.ManagedMediaSource) {
|
|
168
|
+
const isTypeSupportedManaged =
|
|
169
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
170
|
+
ManagedMediaSource.isTypeSupported.bind(ManagedMediaSource);
|
|
171
|
+
|
|
172
|
+
window.ManagedMediaSource.isTypeSupported = (mimeType) => {
|
|
173
|
+
const actualContainer = shaka.util.MimeUtils.getContainerType(mimeType);
|
|
174
|
+
return actualContainer != container && isTypeSupportedManaged(mimeType);
|
|
175
|
+
};
|
|
176
|
+
}
|
|
166
177
|
}
|
|
167
178
|
|
|
168
179
|
/**
|
|
@@ -174,44 +185,25 @@ shaka.polyfill.MediaSource = class {
|
|
|
174
185
|
* @private
|
|
175
186
|
*/
|
|
176
187
|
static rejectCodec_(codec) {
|
|
177
|
-
const isTypeSupported =
|
|
188
|
+
const isTypeSupported =
|
|
189
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
190
|
+
MediaSource.isTypeSupported.bind(MediaSource);
|
|
178
191
|
|
|
179
192
|
MediaSource.isTypeSupported = (mimeType) => {
|
|
180
193
|
const actualCodec = shaka.util.MimeUtils.getCodecBase(mimeType);
|
|
181
194
|
return actualCodec != codec && isTypeSupported(mimeType);
|
|
182
195
|
};
|
|
183
|
-
}
|
|
184
196
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
* @private
|
|
190
|
-
*/
|
|
191
|
-
static patchCastIsTypeSupported_() {
|
|
192
|
-
const originalIsTypeSupported = MediaSource.isTypeSupported;
|
|
193
|
-
|
|
194
|
-
MediaSource.isTypeSupported = (mimeType) => {
|
|
195
|
-
// Parse the basic MIME type from its parameters.
|
|
196
|
-
const pieces = mimeType.split(/ *; */);
|
|
197
|
-
pieces.shift(); // Remove basic MIME type from pieces.
|
|
197
|
+
if (window.ManagedMediaSource) {
|
|
198
|
+
const isTypeSupportedManaged =
|
|
199
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
200
|
+
ManagedMediaSource.isTypeSupported.bind(ManagedMediaSource);
|
|
198
201
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
// isTypeSupported.
|
|
205
|
-
return originalIsTypeSupported(mimeType);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Only canDisplayType can check extended MIME type parameters on this
|
|
209
|
-
// platform (such as frame rate, resolution, etc).
|
|
210
|
-
// In previous versions of this polyfill, the MIME type parameters were
|
|
211
|
-
// manipulated, filtered, or extended. This is no longer true, so we pass
|
|
212
|
-
// the full MIME type to the platform as we received it.
|
|
213
|
-
return cast.__platform__.canDisplayType(mimeType);
|
|
214
|
-
};
|
|
202
|
+
window.ManagedMediaSource.isTypeSupported = (mimeType) => {
|
|
203
|
+
const actualCodec = shaka.util.MimeUtils.getCodecBase(mimeType);
|
|
204
|
+
return actualCodec != codec && isTypeSupportedManaged(mimeType);
|
|
205
|
+
};
|
|
206
|
+
}
|
|
215
207
|
}
|
|
216
208
|
|
|
217
209
|
/**
|
|
@@ -84,51 +84,16 @@ shaka.text.VttTextParser = class {
|
|
|
84
84
|
// HLS content, which should use X-TIMESTAMP-MAP and periodStart instead.
|
|
85
85
|
let offset = time.vttOffset;
|
|
86
86
|
|
|
87
|
-
// Only use 'X-TIMESTAMP-MAP'
|
|
88
|
-
|
|
89
|
-
// timestamp has already been extracted, and appears in periodStart.
|
|
90
|
-
if (blocks[0].includes('X-TIMESTAMP-MAP') && this.sequenceMode_) {
|
|
91
|
-
// https://bit.ly/2K92l7y
|
|
92
|
-
// The 'X-TIMESTAMP-MAP' header is used in HLS to align text with
|
|
93
|
-
// the rest of the media.
|
|
94
|
-
// The header format is 'X-TIMESTAMP-MAP=MPEGTS:n,LOCAL:m'
|
|
95
|
-
// (the attributes can go in any order)
|
|
96
|
-
// where n is MPEG-2 time and m is cue time it maps to.
|
|
97
|
-
// For example 'X-TIMESTAMP-MAP=LOCAL:00:00:00.000,MPEGTS:900000'
|
|
98
|
-
// means an offset of 10 seconds
|
|
99
|
-
// 900000/MPEG_TIMESCALE - cue time.
|
|
100
|
-
const cueTimeMatch =
|
|
101
|
-
blocks[0].match(/LOCAL:((?:(\d{1,}):)?(\d{2}):(\d{2})\.(\d{3}))/m);
|
|
102
|
-
|
|
103
|
-
const mpegTimeMatch = blocks[0].match(/MPEGTS:(\d+)/m);
|
|
104
|
-
if (cueTimeMatch && mpegTimeMatch) {
|
|
105
|
-
const parser = new shaka.util.TextParser(cueTimeMatch[1]);
|
|
106
|
-
const cueTime = shaka.text.VttTextParser.parseTime_(parser);
|
|
107
|
-
if (cueTime == null) {
|
|
108
|
-
throw new shaka.util.Error(
|
|
109
|
-
shaka.util.Error.Severity.CRITICAL,
|
|
110
|
-
shaka.util.Error.Category.TEXT,
|
|
111
|
-
shaka.util.Error.Code.INVALID_TEXT_HEADER);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
let mpegTime = Number(mpegTimeMatch[1]);
|
|
115
|
-
const mpegTimescale = shaka.text.VttTextParser.MPEG_TIMESCALE_;
|
|
116
|
-
|
|
117
|
-
const rolloverSeconds =
|
|
118
|
-
shaka.text.VttTextParser.TS_ROLLOVER_ / mpegTimescale;
|
|
119
|
-
let segmentStart = time.segmentStart - time.periodStart;
|
|
120
|
-
while (segmentStart >= rolloverSeconds) {
|
|
121
|
-
segmentStart -= rolloverSeconds;
|
|
122
|
-
mpegTime += shaka.text.VttTextParser.TS_ROLLOVER_;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
offset = time.periodStart + mpegTime / mpegTimescale - cueTime;
|
|
126
|
-
}
|
|
127
|
-
} else if (blocks[0].includes('X-TIMESTAMP-MAP') &&
|
|
87
|
+
// Only use 'X-TIMESTAMP-MAP' with HLS. This overrides offset above.
|
|
88
|
+
if (blocks[0].includes('X-TIMESTAMP-MAP') &&
|
|
128
89
|
this.manifestType_ == shaka.media.ManifestParser.HLS) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
90
|
+
if (this.sequenceMode_) {
|
|
91
|
+
// Compute a different, rollover-based offset for sequence mode.
|
|
92
|
+
offset = this.computeHlsSequenceModeOffset_(blocks[0], time);
|
|
93
|
+
} else {
|
|
94
|
+
// Calculate the offset from the segment startTime.
|
|
95
|
+
offset = time.segmentStart;
|
|
96
|
+
}
|
|
132
97
|
}
|
|
133
98
|
|
|
134
99
|
// Parse VTT regions.
|
|
@@ -159,6 +124,48 @@ shaka.text.VttTextParser = class {
|
|
|
159
124
|
return ret;
|
|
160
125
|
}
|
|
161
126
|
|
|
127
|
+
/**
|
|
128
|
+
* @param {string} headerBlock Contains X-TIMESTAMP-MAP.
|
|
129
|
+
* @param {shaka.extern.TextParser.TimeContext} time
|
|
130
|
+
* @return {number}
|
|
131
|
+
* @private
|
|
132
|
+
*/
|
|
133
|
+
computeHlsSequenceModeOffset_(headerBlock, time) {
|
|
134
|
+
// https://bit.ly/2K92l7y
|
|
135
|
+
// The 'X-TIMESTAMP-MAP' header is used in HLS to align text with
|
|
136
|
+
// the rest of the media.
|
|
137
|
+
// The header format is 'X-TIMESTAMP-MAP=MPEGTS:n,LOCAL:m'
|
|
138
|
+
// (the attributes can go in any order)
|
|
139
|
+
// where n is MPEG-2 time and m is cue time it maps to.
|
|
140
|
+
// For example 'X-TIMESTAMP-MAP=LOCAL:00:00:00.000,MPEGTS:900000'
|
|
141
|
+
// means an offset of 10 seconds
|
|
142
|
+
// 900000/MPEG_TIMESCALE - cue time.
|
|
143
|
+
const cueTimeMatch = headerBlock.match(
|
|
144
|
+
/LOCAL:((?:(\d{1,}):)?(\d{2}):(\d{2})\.(\d{3}))/m);
|
|
145
|
+
const mpegTimeMatch = headerBlock.match(/MPEGTS:(\d+)/m);
|
|
146
|
+
|
|
147
|
+
if (!cueTimeMatch || !mpegTimeMatch) {
|
|
148
|
+
throw new shaka.util.Error(
|
|
149
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
150
|
+
shaka.util.Error.Category.TEXT,
|
|
151
|
+
shaka.util.Error.Code.INVALID_TEXT_HEADER);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const parser = new shaka.util.TextParser(cueTimeMatch[1]);
|
|
155
|
+
const cueTime = shaka.text.VttTextParser.parseTime_(parser);
|
|
156
|
+
if (cueTime == null) {
|
|
157
|
+
throw new shaka.util.Error(
|
|
158
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
159
|
+
shaka.util.Error.Category.TEXT,
|
|
160
|
+
shaka.util.Error.Code.INVALID_TEXT_HEADER);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const mpegTime = Number(mpegTimeMatch[1]);
|
|
164
|
+
const mpegTimescale = shaka.text.VttTextParser.MPEG_TIMESCALE_;
|
|
165
|
+
|
|
166
|
+
return time.periodStart + mpegTime / mpegTimescale - cueTime;
|
|
167
|
+
}
|
|
168
|
+
|
|
162
169
|
/**
|
|
163
170
|
* Add default color
|
|
164
171
|
*
|
|
@@ -687,6 +694,8 @@ shaka.text.VttTextParser = class {
|
|
|
687
694
|
refCue.fontFamily, cue.fontFamily);
|
|
688
695
|
cue.fontSize = VttTextParser.getOrDefault_(
|
|
689
696
|
refCue.fontSize, cue.fontSize);
|
|
697
|
+
cue.textShadow = VttTextParser.getOrDefault_(
|
|
698
|
+
refCue.textShadow, cue.textShadow);
|
|
690
699
|
|
|
691
700
|
// Overwrite with new values as unable to determine
|
|
692
701
|
// if new value is set or not
|
|
@@ -695,7 +704,6 @@ shaka.text.VttTextParser = class {
|
|
|
695
704
|
cue.opacity = refCue.opacity;
|
|
696
705
|
cue.rubyTag = refCue.rubyTag;
|
|
697
706
|
cue.textCombineUpright = refCue.textCombineUpright;
|
|
698
|
-
cue.textShadow = refCue.textShadow;
|
|
699
707
|
cue.wrapLine = refCue.wrapLine;
|
|
700
708
|
}
|
|
701
709
|
|
|
@@ -1060,13 +1068,6 @@ shaka.text.VttTextParser = class {
|
|
|
1060
1068
|
*/
|
|
1061
1069
|
shaka.text.VttTextParser.MPEG_TIMESCALE_ = 90000;
|
|
1062
1070
|
|
|
1063
|
-
/**
|
|
1064
|
-
* At this value, timestamps roll over in TS content.
|
|
1065
|
-
* @const {number}
|
|
1066
|
-
* @private
|
|
1067
|
-
*/
|
|
1068
|
-
shaka.text.VttTextParser.TS_ROLLOVER_ = 0x200000000;
|
|
1069
|
-
|
|
1070
1071
|
/**
|
|
1071
1072
|
* @const
|
|
1072
1073
|
* @private {!RegExp}
|
package/lib/transmuxer/h264.js
CHANGED
|
@@ -144,7 +144,7 @@ shaka.transmuxer.H264 = class {
|
|
|
144
144
|
const vSpacingTable = [
|
|
145
145
|
1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1,
|
|
146
146
|
];
|
|
147
|
-
if (aspectRatioIdc > 0 && aspectRatioIdc
|
|
147
|
+
if (aspectRatioIdc > 0 && aspectRatioIdc <= 16) {
|
|
148
148
|
hSpacing = hSpacingTable[aspectRatioIdc - 1];
|
|
149
149
|
vSpacing = vSpacingTable[aspectRatioIdc - 1];
|
|
150
150
|
} else if (aspectRatioIdc === 255) {
|
|
@@ -267,8 +267,8 @@ shaka.transmuxer.H264 = class {
|
|
|
267
267
|
naluLength[1] = (size >> 16) & 0xff;
|
|
268
268
|
naluLength[2] = (size >> 8) & 0xff;
|
|
269
269
|
naluLength[3] = size & 0xff;
|
|
270
|
-
nalusData.push(
|
|
271
|
-
|
|
270
|
+
nalusData.push(naluLength);
|
|
271
|
+
nalusData.push(nalu.fullData);
|
|
272
272
|
}
|
|
273
273
|
}
|
|
274
274
|
if (!nalusData.length) {
|
package/lib/transmuxer/h265.js
CHANGED
|
@@ -317,7 +317,7 @@ shaka.transmuxer.H265 = class {
|
|
|
317
317
|
const sarHeightTable = [
|
|
318
318
|
1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1,
|
|
319
319
|
];
|
|
320
|
-
if (aspectRatioIdc > 0 && aspectRatioIdc
|
|
320
|
+
if (aspectRatioIdc > 0 && aspectRatioIdc <= 16) {
|
|
321
321
|
sarWidth = sarWidthTable[aspectRatioIdc - 1];
|
|
322
322
|
sarHeight = sarHeightTable[aspectRatioIdc - 1];
|
|
323
323
|
} else if (aspectRatioIdc === 255) {
|
|
@@ -652,8 +652,8 @@ shaka.transmuxer.H265 = class {
|
|
|
652
652
|
naluLength[1] = (size >> 16) & 0xff;
|
|
653
653
|
naluLength[2] = (size >> 8) & 0xff;
|
|
654
654
|
naluLength[3] = size & 0xff;
|
|
655
|
-
nalusData.push(
|
|
656
|
-
|
|
655
|
+
nalusData.push(naluLength);
|
|
656
|
+
nalusData.push(nalu.fullData);
|
|
657
657
|
}
|
|
658
658
|
}
|
|
659
659
|
if (!nalusData.length) {
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
goog.provide('shaka.transmuxer.TsTransmuxer');
|
|
8
8
|
|
|
9
9
|
goog.require('shaka.media.Capabilities');
|
|
10
|
+
goog.require('shaka.transmuxer.AacTransmuxer');
|
|
10
11
|
goog.require('shaka.transmuxer.Ac3');
|
|
11
12
|
goog.require('shaka.transmuxer.ADTS');
|
|
12
13
|
goog.require('shaka.transmuxer.Ec3');
|
|
@@ -16,6 +17,7 @@ goog.require('shaka.transmuxer.MpegAudio');
|
|
|
16
17
|
goog.require('shaka.transmuxer.TransmuxerEngine');
|
|
17
18
|
goog.require('shaka.util.BufferUtils');
|
|
18
19
|
goog.require('shaka.util.Error');
|
|
20
|
+
goog.require('shaka.util.Id3Utils');
|
|
19
21
|
goog.require('shaka.util.ManifestParserUtils');
|
|
20
22
|
goog.require('shaka.util.MimeUtils');
|
|
21
23
|
goog.require('shaka.util.Mp4Generator');
|
|
@@ -45,6 +47,9 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
45
47
|
|
|
46
48
|
/** @private {?shaka.util.TsParser} */
|
|
47
49
|
this.tsParser_ = null;
|
|
50
|
+
|
|
51
|
+
/** @private {?shaka.transmuxer.AacTransmuxer} */
|
|
52
|
+
this.aacTransmuxer_ = null;
|
|
48
53
|
}
|
|
49
54
|
|
|
50
55
|
|
|
@@ -54,6 +59,10 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
54
59
|
*/
|
|
55
60
|
destroy() {
|
|
56
61
|
this.initSegments.clear();
|
|
62
|
+
|
|
63
|
+
if (this.aacTransmuxer_) {
|
|
64
|
+
this.aacTransmuxer_.destroy();
|
|
65
|
+
}
|
|
57
66
|
}
|
|
58
67
|
|
|
59
68
|
|
|
@@ -187,14 +196,44 @@ shaka.transmuxer.TsTransmuxer = class {
|
|
|
187
196
|
*/
|
|
188
197
|
transmux(data, stream, reference, duration, contentType) {
|
|
189
198
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
199
|
+
const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
|
|
200
|
+
|
|
201
|
+
const uint8ArrayData = shaka.util.BufferUtils.toUint8(data);
|
|
202
|
+
|
|
203
|
+
if (contentType == ContentType.AUDIO &&
|
|
204
|
+
!shaka.util.TsParser.probe(uint8ArrayData)) {
|
|
205
|
+
const id3Data = shaka.util.Id3Utils.getID3Data(uint8ArrayData);
|
|
206
|
+
let offset = id3Data.length;
|
|
207
|
+
for (; offset < uint8ArrayData.length; offset++) {
|
|
208
|
+
if (shaka.transmuxer.MpegAudio.probe(uint8ArrayData, offset)) {
|
|
209
|
+
return Promise.reject(new shaka.util.Error(
|
|
210
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
211
|
+
shaka.util.Error.Category.MEDIA,
|
|
212
|
+
shaka.util.Error.Code.TRANSMUXING_FAILED));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
offset = id3Data.length;
|
|
216
|
+
for (; offset < uint8ArrayData.length; offset++) {
|
|
217
|
+
if (shaka.transmuxer.ADTS.probe(uint8ArrayData, offset)) {
|
|
218
|
+
if (!this.aacTransmuxer_) {
|
|
219
|
+
this.aacTransmuxer_ =
|
|
220
|
+
new shaka.transmuxer.AacTransmuxer('audio/aac');
|
|
221
|
+
}
|
|
222
|
+
return this.aacTransmuxer_
|
|
223
|
+
.transmux(data, stream, reference, duration, contentType);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return Promise.reject(new shaka.util.Error(
|
|
227
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
228
|
+
shaka.util.Error.Category.MEDIA,
|
|
229
|
+
shaka.util.Error.Code.TRANSMUXING_FAILED));
|
|
230
|
+
}
|
|
231
|
+
|
|
190
232
|
if (!this.tsParser_) {
|
|
191
233
|
this.tsParser_ = new shaka.util.TsParser();
|
|
192
234
|
} else {
|
|
193
235
|
this.tsParser_.clearData();
|
|
194
236
|
}
|
|
195
|
-
const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
|
|
196
|
-
|
|
197
|
-
const uint8ArrayData = shaka.util.BufferUtils.toUint8(data);
|
|
198
237
|
|
|
199
238
|
const tsParser = this.tsParser_.parse(uint8ArrayData);
|
|
200
239
|
const streamInfos = [];
|
package/lib/util/error.js
CHANGED
|
@@ -527,6 +527,7 @@ shaka.util.Error.Code = {
|
|
|
527
527
|
* <li>Configure the server to accept a HEAD request for the manifest.
|
|
528
528
|
* </ul>
|
|
529
529
|
* <br> error.data[0] is the manifest URI.
|
|
530
|
+
* <br> error.data[1] is the detected or specified MIME type.
|
|
530
531
|
*/
|
|
531
532
|
'UNABLE_TO_GUESS_MANIFEST_TYPE': 4000,
|
|
532
533
|
|
package/lib/util/mp4_parser.js
CHANGED
|
@@ -271,6 +271,63 @@ shaka.util.Mp4Parser = class {
|
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
|
|
274
|
+
/**
|
|
275
|
+
* A callback that tells the Mp4 parser to treat the body of a box as a audio
|
|
276
|
+
* sample entry. A audio sample entry has some fixed-sized fields
|
|
277
|
+
* describing the audio codec parameters, followed by an arbitrary number of
|
|
278
|
+
* appended children. Each child is a box.
|
|
279
|
+
*
|
|
280
|
+
* @param {!shaka.extern.ParsedBox} box
|
|
281
|
+
* @export
|
|
282
|
+
*/
|
|
283
|
+
static audioSampleEntry(box) {
|
|
284
|
+
// The "reader" starts at the payload, so we need to add the header to the
|
|
285
|
+
// start position. The header size varies.
|
|
286
|
+
const headerSize = shaka.util.Mp4Parser.headerSize(box);
|
|
287
|
+
|
|
288
|
+
// 6 bytes reserved
|
|
289
|
+
// 2 bytes data reference index
|
|
290
|
+
box.reader.skip(8);
|
|
291
|
+
// 2 bytes version
|
|
292
|
+
const version = box.reader.readUint16();
|
|
293
|
+
// 2 bytes revision (0, could be ignored)
|
|
294
|
+
// 4 bytes reserved
|
|
295
|
+
box.reader.skip(6);
|
|
296
|
+
|
|
297
|
+
if (version == 2) {
|
|
298
|
+
// 16 bytes hard-coded values with no comments
|
|
299
|
+
// 8 bytes sample rate
|
|
300
|
+
// 4 bytes channel count
|
|
301
|
+
// 4 bytes hard-coded values with no comments
|
|
302
|
+
// 4 bytes bits per sample
|
|
303
|
+
// 4 bytes lpcm flags
|
|
304
|
+
// 4 bytes sample size
|
|
305
|
+
// 4 bytes samples per packet
|
|
306
|
+
box.reader.skip(48);
|
|
307
|
+
} else {
|
|
308
|
+
// 2 bytes channel count
|
|
309
|
+
// 2 bytes bits per sample
|
|
310
|
+
// 2 bytes compression ID
|
|
311
|
+
// 2 bytes packet size
|
|
312
|
+
// 2 bytes sample rate
|
|
313
|
+
// 2 byte reserved
|
|
314
|
+
box.reader.skip(12);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (version == 1) {
|
|
318
|
+
// 4 bytes samples per packet
|
|
319
|
+
// 4 bytes bytes per packet
|
|
320
|
+
// 4 bytes bytes per frame
|
|
321
|
+
// 4 bytes bytes per sample
|
|
322
|
+
box.reader.skip(16);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
while (box.reader.hasMoreData() && !box.parser.done_) {
|
|
326
|
+
box.parser.parseNext(box.start + headerSize, box.reader, box.partialOkay);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
|
|
274
331
|
/**
|
|
275
332
|
* Create a callback that tells the Mp4 parser to treat the body of a box as a
|
|
276
333
|
* binary blob and to parse the body's contents using the provided callback.
|
package/lib/util/platform.js
CHANGED
|
@@ -535,6 +535,10 @@ shaka.util.Platform = class {
|
|
|
535
535
|
Platform.isWebOS4() || Platform.isWebOS5()) {
|
|
536
536
|
return false;
|
|
537
537
|
}
|
|
538
|
+
// See: https://chromium-review.googlesource.com/c/chromium/src/+/4577759
|
|
539
|
+
if (Platform.isWindows() && Platform.isEdge()) {
|
|
540
|
+
return false;
|
|
541
|
+
}
|
|
538
542
|
return true;
|
|
539
543
|
}
|
|
540
544
|
|