shaka-player 4.2.10 → 4.2.11
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/demo-version-index.yaml +3 -3
- package/CHANGELOG.md +17 -0
- package/README.md +3 -0
- package/demo/demo.less +1 -0
- package/dist/demo.css +1 -1
- package/dist/demo.css.map +1 -1
- package/dist/locales.js +30 -30
- package/dist/shaka-player.compiled.d.ts +8 -0
- package/dist/shaka-player.compiled.debug.d.ts +8 -0
- package/dist/shaka-player.compiled.debug.externs.js +9 -0
- package/dist/shaka-player.compiled.debug.js +40 -38
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.externs.js +9 -0
- package/dist/shaka-player.compiled.js +425 -424
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.d.ts +8 -0
- package/dist/shaka-player.ui.debug.d.ts +8 -0
- package/dist/shaka-player.ui.debug.externs.js +9 -0
- package/dist/shaka-player.ui.debug.js +166 -164
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.externs.js +9 -0
- package/dist/shaka-player.ui.js +234 -233
- package/dist/shaka-player.ui.map +3 -3
- package/docs/tutorials/welcome.md +1 -1
- package/lib/hls/hls_parser.js +6 -0
- package/lib/hls/manifest_text_parser.js +10 -1
- package/lib/media/drm_engine.js +9 -6
- package/lib/media/media_source_engine.js +6 -4
- package/lib/media/segment_reference.js +22 -0
- package/lib/media/streaming_engine.js +9 -4
- package/lib/player.js +5 -1
- package/package.json +9 -3
- package/test/hls/hls_live_unit.js +3 -1
- package/test/media/media_source_engine_unit.js +31 -0
- package/test/test/util/layout_tests.js +4 -3
|
@@ -29,7 +29,7 @@ You can build Shaka on Linux, Windows, or Mac.
|
|
|
29
29
|
To get the sources and compile the library, you will need:
|
|
30
30
|
* {@link https://git-scm.com/downloads Git v1.9+}
|
|
31
31
|
* {@link https://www.python.org/downloads/ Python v2.7 or v3.5+}
|
|
32
|
-
* {@link https://
|
|
32
|
+
* {@link https://learn.microsoft.com/en-us/java/openjdk/download Java Runtime Environment v14+}
|
|
33
33
|
* {@link https://nodejs.org/en/download/ NodeJS v14+}
|
|
34
34
|
* A local web server, such as {@link https://httpd.apache.org/ Apache}
|
|
35
35
|
* _NOTE: A local web server is required because browsers place restrictions
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -2131,6 +2131,9 @@ shaka.hls.HlsParser = class {
|
|
|
2131
2131
|
/* tileDuration= */ null,
|
|
2132
2132
|
/* syncTime= */ null,
|
|
2133
2133
|
partialStatus);
|
|
2134
|
+
if (item.name == 'EXT-X-PRELOAD-HINT') {
|
|
2135
|
+
partial.markAsPreload();
|
|
2136
|
+
}
|
|
2134
2137
|
partialSegmentRefs.push(partial);
|
|
2135
2138
|
} // for-loop of hlsSegment.partialSegments
|
|
2136
2139
|
}
|
|
@@ -2451,6 +2454,9 @@ shaka.hls.HlsParser = class {
|
|
|
2451
2454
|
* @private
|
|
2452
2455
|
*/
|
|
2453
2456
|
variableSubstitution_(uri, variables) {
|
|
2457
|
+
if (!variables.size) {
|
|
2458
|
+
return uri;
|
|
2459
|
+
}
|
|
2454
2460
|
let newUri = String(uri).replace(/%7B/g, '{').replace(/%7D/g, '}');
|
|
2455
2461
|
|
|
2456
2462
|
const uriVariables = newUri.match(/{\$\w*}/g);
|
|
@@ -158,7 +158,15 @@ shaka.hls.ManifestTextParser = class {
|
|
|
158
158
|
partialSegmentTags.push(tag);
|
|
159
159
|
} else if (tag.name == 'EXT-X-PRELOAD-HINT') {
|
|
160
160
|
if (tag.getAttributeValue('TYPE') == 'PART') {
|
|
161
|
-
|
|
161
|
+
// Note: BYTERANGE-START without BYTERANGE-LENGTH is being
|
|
162
|
+
// ignored.
|
|
163
|
+
if (tag.getAttributeValue('BYTERANGE-START') != null) {
|
|
164
|
+
if (tag.getAttributeValue('BYTERANGE-LENGTH') != null) {
|
|
165
|
+
partialSegmentTags.push(tag);
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
partialSegmentTags.push(tag);
|
|
169
|
+
}
|
|
162
170
|
} else if (tag.getAttributeValue('TYPE') == 'MAP') {
|
|
163
171
|
// Rename the Preload Hint tag to be a Map tag.
|
|
164
172
|
tag.setName('EXT-X-MAP');
|
|
@@ -300,6 +308,7 @@ shaka.hls.ManifestTextParser.MEDIA_PLAYLIST_TAGS = [
|
|
|
300
308
|
'EXT-X-ENDLIST',
|
|
301
309
|
'EXT-X-SERVER-CONTROL',
|
|
302
310
|
'EXT-X-SKIP',
|
|
311
|
+
'EXT-X-PART-INF',
|
|
303
312
|
];
|
|
304
313
|
|
|
305
314
|
|
package/lib/media/drm_engine.js
CHANGED
|
@@ -133,6 +133,9 @@ shaka.media.DrmEngine = class {
|
|
|
133
133
|
|
|
134
134
|
/** @private {Promise} */
|
|
135
135
|
this.mediaKeysAttached_ = null;
|
|
136
|
+
|
|
137
|
+
/** @private {?shaka.extern.InitDataOverride} */
|
|
138
|
+
this.manifestInitData_ = null;
|
|
136
139
|
}
|
|
137
140
|
|
|
138
141
|
/** @override */
|
|
@@ -480,10 +483,10 @@ shaka.media.DrmEngine = class {
|
|
|
480
483
|
() => this.closeOpenSessions_());
|
|
481
484
|
}
|
|
482
485
|
|
|
483
|
-
|
|
484
|
-
this.currentDrmInfo_.initData.find(
|
|
486
|
+
this.manifestInitData_ = this.currentDrmInfo_ ?
|
|
487
|
+
(this.currentDrmInfo_.initData.find(
|
|
485
488
|
(initDataOverride) => initDataOverride.initData.length > 0,
|
|
486
|
-
) : null;
|
|
489
|
+
) || null) : null;
|
|
487
490
|
|
|
488
491
|
/**
|
|
489
492
|
* We can attach media keys before the playback actually begins when:
|
|
@@ -491,7 +494,7 @@ shaka.media.DrmEngine = class {
|
|
|
491
494
|
* - Some initData already has been generated (through the manifest)
|
|
492
495
|
* - In case of an offline session
|
|
493
496
|
*/
|
|
494
|
-
if (
|
|
497
|
+
if (this.manifestInitData_ ||
|
|
495
498
|
this.currentDrmInfo_.keySystem !== 'com.apple.fps' ||
|
|
496
499
|
this.offlineSessionIds_.length) {
|
|
497
500
|
await this.attachMediaKeys_();
|
|
@@ -504,7 +507,7 @@ shaka.media.DrmEngine = class {
|
|
|
504
507
|
// Also suppress 'encrypted' events when parsing in-band ppsh
|
|
505
508
|
// from media segments because that serves the same purpose as the
|
|
506
509
|
// 'encrypted' events.
|
|
507
|
-
if (!
|
|
510
|
+
if (!this.manifestInitData_ && !this.offlineSessionIds_.length &&
|
|
508
511
|
!this.config_.parseInbandPsshEnabled) {
|
|
509
512
|
this.eventManager_.listen(
|
|
510
513
|
this.video_, 'encrypted', (e) => this.onEncryptedEvent_(e));
|
|
@@ -2353,7 +2356,7 @@ shaka.media.DrmEngine = class {
|
|
|
2353
2356
|
* @return {!Promise<void>}
|
|
2354
2357
|
*/
|
|
2355
2358
|
parseInbandPssh(contentType, mediaSegment) {
|
|
2356
|
-
if (!this.config_.parseInbandPsshEnabled) {
|
|
2359
|
+
if (!this.config_.parseInbandPsshEnabled || this.manifestInitData_) {
|
|
2357
2360
|
return Promise.resolve();
|
|
2358
2361
|
}
|
|
2359
2362
|
|
|
@@ -99,15 +99,15 @@ shaka.media.MediaSourceEngine = class {
|
|
|
99
99
|
/** @private {!shaka.util.PublicPromise} */
|
|
100
100
|
this.mediaSourceOpen_ = new shaka.util.PublicPromise();
|
|
101
101
|
|
|
102
|
+
/** @private {string} */
|
|
103
|
+
this.url_ = '';
|
|
104
|
+
|
|
102
105
|
/** @private {MediaSource} */
|
|
103
106
|
this.mediaSource_ = this.createMediaSource(this.mediaSourceOpen_);
|
|
104
107
|
|
|
105
108
|
/** @type {!shaka.util.Destroyer} */
|
|
106
109
|
this.destroyer_ = new shaka.util.Destroyer(() => this.doDestroy_());
|
|
107
110
|
|
|
108
|
-
/** @private {string} */
|
|
109
|
-
this.url_ = '';
|
|
110
|
-
|
|
111
111
|
/** @private {boolean} */
|
|
112
112
|
this.sequenceMode_ = false;
|
|
113
113
|
|
|
@@ -144,6 +144,8 @@ shaka.media.MediaSourceEngine = class {
|
|
|
144
144
|
* @private
|
|
145
145
|
*/
|
|
146
146
|
onSourceOpen_(p) {
|
|
147
|
+
goog.asserts.assert(this.url_, 'Must have object URL');
|
|
148
|
+
|
|
147
149
|
// Release the object URL that was previously created, to prevent memory
|
|
148
150
|
// leak.
|
|
149
151
|
// createObjectURL creates a strong reference to the MediaSource object
|
|
@@ -710,7 +712,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
710
712
|
this.append_(contentType, data);
|
|
711
713
|
});
|
|
712
714
|
|
|
713
|
-
if (goog.DEBUG && reference) {
|
|
715
|
+
if (goog.DEBUG && reference && !reference.isPreload()) {
|
|
714
716
|
const bufferedAfter = this.getBuffered_(contentType);
|
|
715
717
|
const newBuffered = shaka.media.TimeRangesUtils.computeAddedRange(
|
|
716
718
|
bufferedBefore, bufferedAfter);
|
|
@@ -238,6 +238,9 @@ shaka.media.SegmentReference = class {
|
|
|
238
238
|
/** @type {shaka.media.SegmentReference.Status} */
|
|
239
239
|
this.status = status;
|
|
240
240
|
|
|
241
|
+
/** @type {boolean} */
|
|
242
|
+
this.preload = false;
|
|
243
|
+
|
|
241
244
|
/** @type {?shaka.extern.HlsAes128Key} */
|
|
242
245
|
this.hlsAes128Key = hlsAes128Key;
|
|
243
246
|
|
|
@@ -358,6 +361,25 @@ shaka.media.SegmentReference = class {
|
|
|
358
361
|
this.status = shaka.media.SegmentReference.Status.UNAVAILABLE;
|
|
359
362
|
}
|
|
360
363
|
|
|
364
|
+
/**
|
|
365
|
+
* Mark the reference as preload.
|
|
366
|
+
*
|
|
367
|
+
* @export
|
|
368
|
+
*/
|
|
369
|
+
markAsPreload() {
|
|
370
|
+
this.preload = true;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Returns true if the segment is preloaded.
|
|
375
|
+
*
|
|
376
|
+
* @return {boolean}
|
|
377
|
+
* @export
|
|
378
|
+
*/
|
|
379
|
+
isPreload() {
|
|
380
|
+
return this.preload;
|
|
381
|
+
}
|
|
382
|
+
|
|
361
383
|
/**
|
|
362
384
|
* Offset the segment reference by a fixed amount.
|
|
363
385
|
*
|
|
@@ -640,10 +640,15 @@ shaka.media.StreamingEngine = class {
|
|
|
640
640
|
const mediaState = this.mediaStates_.get(type);
|
|
641
641
|
const logPrefix = shaka.media.StreamingEngine.logPrefix_(mediaState);
|
|
642
642
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
643
|
+
let segment = null;
|
|
644
|
+
if (mediaState.segmentIterator) {
|
|
645
|
+
segment = mediaState.segmentIterator.current();
|
|
646
|
+
}
|
|
647
|
+
// Only reset the iterator if we seek outside the current segment.
|
|
648
|
+
if (!segment || segment.startTime > presentationTime ||
|
|
649
|
+
segment.endTime < presentationTime) {
|
|
650
|
+
mediaState.segmentIterator = null;
|
|
651
|
+
}
|
|
647
652
|
|
|
648
653
|
if (!newTimeIsBuffered(type)) {
|
|
649
654
|
const bufferEnd =
|
package/lib/player.js
CHANGED
|
@@ -5686,6 +5686,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
5686
5686
|
error.category != shaka.util.Error.Category.NETWORK) {
|
|
5687
5687
|
return false;
|
|
5688
5688
|
}
|
|
5689
|
+
if (this.loadMode_ != shaka.Player.LoadMode.MEDIA_SOURCE) {
|
|
5690
|
+
return false;
|
|
5691
|
+
}
|
|
5692
|
+
goog.asserts.assert(this.manifest_, 'Should have manifest!');
|
|
5689
5693
|
|
|
5690
5694
|
if (!navigator.onLine) {
|
|
5691
5695
|
// Don't restrict variants if we're completely offline, or else we end up
|
|
@@ -6626,7 +6630,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6626
6630
|
* @define {string} A version number taken from git at compile time.
|
|
6627
6631
|
* @export
|
|
6628
6632
|
*/
|
|
6629
|
-
shaka.Player.version = 'v4.2.
|
|
6633
|
+
shaka.Player.version = 'v4.2.11-uncompiled';
|
|
6630
6634
|
|
|
6631
6635
|
// Initialize the deprecation system using the version string we just set
|
|
6632
6636
|
// on the player.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shaka-player",
|
|
3
3
|
"description": "DASH/EME video player library",
|
|
4
|
-
"version": "4.2.
|
|
4
|
+
"version": "4.2.11",
|
|
5
5
|
"homepage": "https://github.com/shaka-project/shaka-player",
|
|
6
6
|
"author": "Google",
|
|
7
7
|
"maintainers": [
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"awesomplete": "^1.1.5",
|
|
19
19
|
"babel-plugin-istanbul": "^6.1.1",
|
|
20
20
|
"cajon": "^0.4.4",
|
|
21
|
+
"clean-package": "^2.2.0",
|
|
21
22
|
"code-prettify": "^0.1.0",
|
|
22
23
|
"color-themes-for-google-code-prettify": "^2.0.4",
|
|
23
24
|
"core-js": "^3.21.1",
|
|
@@ -66,6 +67,7 @@
|
|
|
66
67
|
"demoDeps": [
|
|
67
68
|
"awesomplete/awesomplete.css",
|
|
68
69
|
"awesomplete/awesomplete.min.js",
|
|
70
|
+
"codem-isoboxer/dist/iso_boxer.min.js",
|
|
69
71
|
"dialog-polyfill/dialog-polyfill.css",
|
|
70
72
|
"dialog-polyfill/dist/dialog-polyfill.js",
|
|
71
73
|
"eme-encryption-scheme-polyfill/index.js",
|
|
@@ -91,12 +93,16 @@
|
|
|
91
93
|
},
|
|
92
94
|
"license": "Apache-2.0",
|
|
93
95
|
"scripts": {
|
|
96
|
+
"prepack": "clean-package",
|
|
97
|
+
"postpack": "clean-package restore",
|
|
94
98
|
"prepublishOnly": "python build/checkversion.py && python build/all.py --force"
|
|
95
99
|
},
|
|
96
100
|
"dependencies": {
|
|
97
101
|
"eme-encryption-scheme-polyfill": "^2.1.1"
|
|
98
102
|
},
|
|
99
|
-
"
|
|
100
|
-
"
|
|
103
|
+
"clean-package": {
|
|
104
|
+
"remove": [
|
|
105
|
+
"engines"
|
|
106
|
+
]
|
|
101
107
|
}
|
|
102
108
|
}
|
|
@@ -560,7 +560,8 @@ describe('HlsParser live', () => {
|
|
|
560
560
|
// partialRef3
|
|
561
561
|
'#EXT-X-PART:DURATION=2,URI="partial.mp4",BYTERANGE=210@0\n',
|
|
562
562
|
// preloadRef
|
|
563
|
-
'#EXT-X-PRELOAD-HINT:TYPE=PART,URI="partial.mp4",BYTERANGE-START=210
|
|
563
|
+
'#EXT-X-PRELOAD-HINT:TYPE=PART,URI="partial.mp4",BYTERANGE-START=210,',
|
|
564
|
+
'BYTERANGE-LENGTH=210\n',
|
|
564
565
|
].join('');
|
|
565
566
|
|
|
566
567
|
const partialRef = makeReference(
|
|
@@ -583,6 +584,7 @@ describe('HlsParser live', () => {
|
|
|
583
584
|
const preloadRef = makeReference(
|
|
584
585
|
'test:/partial.mp4', 6, 7.5, /* syncTime= */ null,
|
|
585
586
|
/* baseUri= */ '', /* startByte= */ 210, /* endByte= */ null);
|
|
587
|
+
preloadRef.markAsPreload();
|
|
586
588
|
|
|
587
589
|
// ref2 is not fully published yet, so it doesn't have a segment uri.
|
|
588
590
|
const ref2 = makeReference(
|
|
@@ -165,9 +165,12 @@ describe('MediaSourceEngine', () => {
|
|
|
165
165
|
describe('constructor', () => {
|
|
166
166
|
const originalCreateObjectURL =
|
|
167
167
|
shaka.media.MediaSourceEngine.createObjectURL;
|
|
168
|
+
const originalRevokeObjectURL = window.URL.revokeObjectURL;
|
|
168
169
|
const originalMediaSource = window.MediaSource;
|
|
169
170
|
/** @type {jasmine.Spy} */
|
|
170
171
|
let createObjectURLSpy;
|
|
172
|
+
/** @type {jasmine.Spy} */
|
|
173
|
+
let revokeObjectURLSpy;
|
|
171
174
|
|
|
172
175
|
beforeEach(async () => {
|
|
173
176
|
// Mock out MediaSource so we can test the production version of
|
|
@@ -182,6 +185,9 @@ describe('MediaSourceEngine', () => {
|
|
|
182
185
|
shaka.media.MediaSourceEngine.createObjectURL =
|
|
183
186
|
Util.spyFunc(createObjectURLSpy);
|
|
184
187
|
|
|
188
|
+
revokeObjectURLSpy = jasmine.createSpy('revokeObjectURL');
|
|
189
|
+
window.URL.revokeObjectURL = Util.spyFunc(revokeObjectURLSpy);
|
|
190
|
+
|
|
185
191
|
const mediaSourceSpy = jasmine.createSpy('MediaSource');
|
|
186
192
|
// Because this is a fake constructor, it must be callable with "new".
|
|
187
193
|
// This will cause jasmine to invoke the callback with "new" as well, so
|
|
@@ -199,6 +205,7 @@ describe('MediaSourceEngine', () => {
|
|
|
199
205
|
afterAll(() => {
|
|
200
206
|
shaka.media.MediaSourceEngine.createObjectURL = originalCreateObjectURL;
|
|
201
207
|
window.MediaSource = originalMediaSource;
|
|
208
|
+
window.URL.revokeObjectURL = originalRevokeObjectURL;
|
|
202
209
|
});
|
|
203
210
|
|
|
204
211
|
it('creates a MediaSource object and sets video.src', () => {
|
|
@@ -211,6 +218,30 @@ describe('MediaSourceEngine', () => {
|
|
|
211
218
|
expect(createObjectURLSpy).toHaveBeenCalled();
|
|
212
219
|
expect(mockVideo.src).toBe('blob:foo');
|
|
213
220
|
});
|
|
221
|
+
|
|
222
|
+
it('revokes object URL after MediaSource opens', () => {
|
|
223
|
+
let onSourceOpenListener;
|
|
224
|
+
|
|
225
|
+
mockMediaSource.addEventListener.and.callFake((event, callback, _) => {
|
|
226
|
+
if (event == 'sourceopen') {
|
|
227
|
+
onSourceOpenListener = callback;
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
mediaSourceEngine = new shaka.media.MediaSourceEngine(
|
|
232
|
+
video,
|
|
233
|
+
new shaka.test.FakeClosedCaptionParser(),
|
|
234
|
+
new shaka.test.FakeTextDisplayer());
|
|
235
|
+
|
|
236
|
+
expect(mockMediaSource.addEventListener).toHaveBeenCalledTimes(1);
|
|
237
|
+
expect(mockMediaSource.addEventListener.calls.mostRecent().args[0])
|
|
238
|
+
.toBe('sourceopen');
|
|
239
|
+
expect(typeof onSourceOpenListener).toBe(typeof Function);
|
|
240
|
+
|
|
241
|
+
onSourceOpenListener();
|
|
242
|
+
|
|
243
|
+
expect(revokeObjectURLSpy).toHaveBeenCalledWith('blob:foo');
|
|
244
|
+
});
|
|
214
245
|
});
|
|
215
246
|
|
|
216
247
|
describe('init', () => {
|
|
@@ -43,9 +43,10 @@ shaka.test.LayoutTests = class {
|
|
|
43
43
|
});
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
// Wait one extra
|
|
47
|
-
// updated. Without this, we saw some rare test flake in Firefox on
|
|
48
|
-
|
|
46
|
+
// Wait one extra second to make sure the font rendering on the page has
|
|
47
|
+
// been updated. Without this, we saw some rare test flake in Firefox on
|
|
48
|
+
// Mac.
|
|
49
|
+
await shaka.test.Util.delay(1);
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
/**
|