shaka-player 4.0.1 → 4.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUTHORS +1 -0
- package/CHANGELOG.md +37 -0
- package/CONTRIBUTORS +3 -0
- package/README.md +20 -6
- package/demo/common/assets.js +1 -1
- package/demo/demo.less +0 -1
- package/demo/index.html +0 -2
- package/demo/main.js +3 -3
- package/dist/controls.css +3 -3
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +3 -3
- package/dist/demo.compiled.debug.map +2 -2
- package/dist/demo.compiled.js +3 -3
- package/dist/demo.compiled.map +2 -2
- package/dist/demo.css +1 -1
- package/dist/demo.css.map +1 -1
- package/dist/deps.js +4 -4
- package/dist/locales.js +34 -34
- package/dist/receiver.compiled.debug.js +1 -1
- package/dist/receiver.compiled.debug.map +1 -1
- package/dist/receiver.compiled.js +1 -1
- package/dist/receiver.compiled.map +1 -1
- package/dist/shaka-player.compiled.d.ts +11 -0
- package/dist/shaka-player.compiled.debug.d.ts +11 -0
- package/dist/shaka-player.compiled.debug.externs.js +51 -39
- package/dist/shaka-player.compiled.debug.js +247 -237
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +51 -39
- package/dist/shaka-player.compiled.js +799 -792
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +11 -0
- package/dist/shaka-player.ui.debug.d.ts +11 -0
- package/dist/shaka-player.ui.debug.externs.js +51 -39
- package/dist/shaka-player.ui.debug.js +273 -262
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +51 -39
- package/dist/shaka-player.ui.js +957 -952
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/upgrade.md +1 -0
- package/docs/tutorials/welcome.md +6 -3
- package/externs/shaka/player.js +4 -2
- package/lib/abr/simple_abr_manager.js +2 -1
- package/lib/dash/dash_parser.js +5 -0
- package/lib/hls/hls_parser.js +197 -73
- package/lib/media/drm_engine.js +3 -0
- package/lib/media/media_source_engine.js +57 -24
- package/lib/media/presentation_timeline.js +24 -1
- package/lib/media/segment_index.js +26 -1
- package/lib/media/segment_reference.js +10 -3
- package/lib/media/streaming_engine.js +3 -4
- package/lib/media/time_ranges_utils.js +46 -0
- package/lib/player.js +1 -1
- package/lib/polyfill/media_capabilities.js +3 -0
- package/lib/polyfill/videoplaybackquality.js +3 -1
- package/lib/util/mime_utils.js +14 -5
- package/lib/util/platform.js +19 -1
- package/lib/util/stream_utils.js +1 -0
- package/lib/util/string_utils.js +56 -14
- package/maintained-branches.md +15 -0
- package/package.json +3 -5
- package/test/hls/hls_live_unit.js +57 -7
- package/test/hls/hls_parser_unit.js +102 -8
- package/test/media/drm_engine_integration.js +24 -8
- package/test/media/media_source_engine_integration.js +24 -10
- package/test/media/media_source_engine_unit.js +53 -38
- package/test/media/streaming_engine_unit.js +28 -27
- package/test/test/util/fake_media_source_engine.js +10 -9
- package/ui/less/containers.less +1 -1
- package/ui/less/general.less +1 -1
- package/ui/less/range_elements.less +1 -0
- package/.github/pull_request_template.md +0 -10
- package/app-engine/README.md +0 -9
- package/app-engine/demo-version-index/README.md +0 -14
- package/app-engine/demo-version-index/app.yaml +0 -28
- package/app-engine/demo-version-index/generate.py +0 -164
- package/app-engine/demo-version-index/main.py +0 -11
- package/app-engine/demo-version-index/requirements.txt +0 -5
- package/app-engine/demo-version-index/templates/index.html +0 -114
- package/app-engine/shaka-player-demo/README.md +0 -18
- package/app-engine/shaka-player-demo/app.yaml +0 -61
- package/app-engine/shaka-player-demo/main.py +0 -95
- package/app-engine/shaka-player-demo/posters/10yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/10yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/1yo.jpg +0 -0
- package/app-engine/shaka-player-demo/posters/2yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/2yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/3yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/3yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/4yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/4yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/5yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/5yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/6yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/6yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/7yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/7yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/8yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/8yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/9yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/9yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/audioOnly.gif +0 -0
- package/app-engine/shaka-player-demo/posters/audioRickRoll.gif +0 -0
- package/app-engine/shaka-player-demo/posters/colorbars.gif +0 -0
- package/app-engine/shaka-player-demo/posters/fireworks.jpg +0 -0
- package/app-engine/shaka-player-demo/posters/party-hat.png +0 -0
- package/app-engine/shaka-player-demo/posters/sources.txt +0 -46
- package/app-engine/shaka-player-demo/posters/standard.png +0 -0
- package/app-engine/shaka-player-demo/posters/trek.jpg +0 -0
- package/app-engine/shaka-player-demo/posters/valentines.png +0 -0
- package/app-engine/shaka-player-demo/posters/zombie.jpg +0 -0
- package/app-engine/shaka-player-demo/posters.py +0 -110
- package/app-engine/shaka-player-demo/requirements.txt +0 -5
- package/app-engine/shaka-player-demo/time.txt +0 -1
- package/build/README.md +0 -127
- package/build/__init__.py +0 -0
- package/build/all.py +0 -150
- package/build/apps.py +0 -186
- package/build/build.py +0 -392
- package/build/check.py +0 -354
- package/build/checkversion.py +0 -84
- package/build/compiler.py +0 -513
- package/build/conformance.textproto +0 -335
- package/build/docker/Dockerfile +0 -20
- package/build/docker/docker-compose.yml +0 -10
- package/build/docs.py +0 -54
- package/build/eslint-plugin-shaka-rules/arg-comment-spacing.js +0 -72
- package/build/eslint-plugin-shaka-rules/index.js +0 -24
- package/build/eslint-plugin-shaka-rules/package.json +0 -7
- package/build/eslint-plugin-shaka-rules/private.js +0 -109
- package/build/gendeps.py +0 -71
- package/build/generateExterns.js +0 -867
- package/build/generateLocalizations.py +0 -262
- package/build/generateTsDefs.py +0 -137
- package/build/install-linux-prereqs.sh +0 -136
- package/build/license-header +0 -5
- package/build/misspellings.txt +0 -39
- package/build/pixelsChanged.js +0 -35
- package/build/shaka-lab.yaml +0 -161
- package/build/shakaBuildHelpers.py +0 -356
- package/build/stats.py +0 -816
- package/build/subprocessWindowsPatch.py +0 -103
- package/build/test.py +0 -541
- package/build/types/ads +0 -8
- package/build/types/cast +0 -6
- package/build/types/cea +0 -13
- package/build/types/complete +0 -9
- package/build/types/core +0 -108
- package/build/types/dash +0 -8
- package/build/types/hls +0 -9
- package/build/types/manifests +0 -5
- package/build/types/networking +0 -6
- package/build/types/offline +0 -22
- package/build/types/polyfill +0 -18
- package/build/types/text +0 -11
- package/build/types/ui +0 -39
- package/build/updateScreenshots.py +0 -85
- package/build/wrapper.template.js +0 -52
|
@@ -25,6 +25,7 @@ application:
|
|
|
25
25
|
- TextDecoder/TextEncoder platform support or polyfill required (affects
|
|
26
26
|
Xbox One, but not evergreen browsers); we suggest the polyfill
|
|
27
27
|
[https://github.com/anonyco/FastestSmallestTextEncoderDecoder](fastestsmallesttextencoderdecoder/EncoderDecoderTogether.min.js)
|
|
28
|
+
Fallback included by default in v4.2
|
|
28
29
|
|
|
29
30
|
- Support removed:
|
|
30
31
|
- IE11 support removed
|
|
@@ -98,11 +98,14 @@ You can find a full list of available browsers with `--browsers help`, and you
|
|
|
98
98
|
can find a complete list of testing options with `--help`.
|
|
99
99
|
|
|
100
100
|
|
|
101
|
-
####
|
|
101
|
+
#### Announcements
|
|
102
102
|
|
|
103
|
-
|
|
103
|
+
To subscribe to new releases on GitHub, you can follow
|
|
104
|
+
[instructions from this blog](https://www.jessesquires.com/blog/2020/07/30/github-tip-watching-releases/).
|
|
105
|
+
|
|
106
|
+
To receive infrequent announcements and surveys from us, you can join our
|
|
104
107
|
[mailing list](https://groups.google.com/forum/#!forum/shaka-player-users).
|
|
105
|
-
The list is very low volume.
|
|
108
|
+
The list is very low volume, and can only be written to by us.
|
|
106
109
|
|
|
107
110
|
|
|
108
111
|
#### Continue the Tutorials
|
package/externs/shaka/player.js
CHANGED
|
@@ -766,8 +766,10 @@ shaka.extern.DashManifestConfiguration;
|
|
|
766
766
|
* <i>Defaults to <code>'avc1.42E01E'</code>.</i>
|
|
767
767
|
* @property {boolean} ignoreManifestProgramDateTime
|
|
768
768
|
* If <code>true</code>, the HLS parser will ignore the
|
|
769
|
-
* <code>EXT-X-PROGRAM-DATE-TIME</code> tags in the manifest
|
|
770
|
-
*
|
|
769
|
+
* <code>EXT-X-PROGRAM-DATE-TIME</code> tags in the manifest and use media
|
|
770
|
+
* sequence numbers instead.
|
|
771
|
+
* Meant for streams where <code>EXT-X-PROGRAM-DATE-TIME</code> is incorrect
|
|
772
|
+
* or malformed.
|
|
771
773
|
* <i>Defaults to <code>false</code>.</i>
|
|
772
774
|
* @property {string} mediaPlaylistFullMimeType
|
|
773
775
|
* A string containing a full mime type, including both the basic mime type
|
|
@@ -219,8 +219,9 @@ shaka.abr.SimpleAbrManager = class {
|
|
|
219
219
|
* @export
|
|
220
220
|
*/
|
|
221
221
|
getBandwidthEstimate() {
|
|
222
|
+
const defaultBandwidthEstimate = this.getDefaultBandwidth_();
|
|
222
223
|
return this.bandwidthEstimator_.getBandwidthEstimate(
|
|
223
|
-
|
|
224
|
+
defaultBandwidthEstimate);
|
|
224
225
|
}
|
|
225
226
|
|
|
226
227
|
|
package/lib/dash/dash_parser.js
CHANGED
|
@@ -513,6 +513,11 @@ shaka.dash.DashParser = class {
|
|
|
513
513
|
}
|
|
514
514
|
presentationTimeline.setClockOffset(offset);
|
|
515
515
|
}
|
|
516
|
+
|
|
517
|
+
// This is the first point where we have a meaningful presentation start
|
|
518
|
+
// time, and we need to tell PresentationTimeline that so that it can
|
|
519
|
+
// maintain consistency from here on.
|
|
520
|
+
presentationTimeline.lockStartTime();
|
|
516
521
|
} else {
|
|
517
522
|
// Just update the variants and text streams, which may change as periods
|
|
518
523
|
// are added or removed.
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -121,13 +121,19 @@ shaka.hls.HlsParser = class {
|
|
|
121
121
|
this.updatePlaylistDelay_ = 0;
|
|
122
122
|
|
|
123
123
|
/**
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
|
|
124
|
+
* If true, we have already calculated offsets to synchronize streams.
|
|
125
|
+
* Offsets are computed in syncStreams*_().
|
|
126
|
+
* @private {boolean}
|
|
127
|
+
*/
|
|
128
|
+
this.streamsSynced_ = false;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The minimum sequence number for generated segments, when ignoring
|
|
132
|
+
* EXT-X-PROGRAM-DATE-TIME.
|
|
133
|
+
*
|
|
128
134
|
* @private {?number}
|
|
129
135
|
*/
|
|
130
|
-
this.
|
|
136
|
+
this.minSequenceNumber_ = null;
|
|
131
137
|
|
|
132
138
|
/**
|
|
133
139
|
* This timer is used to trigger the start of a manifest update. A manifest
|
|
@@ -361,39 +367,155 @@ shaka.hls.HlsParser = class {
|
|
|
361
367
|
}
|
|
362
368
|
|
|
363
369
|
/**
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
* measured in time since 1970.
|
|
370
|
+
* Align all streams by sequence number by dropping early segments. Then
|
|
371
|
+
* offset all streams to begin at presentation time 0.
|
|
367
372
|
* @private
|
|
368
373
|
*/
|
|
369
|
-
|
|
370
|
-
if (this.
|
|
371
|
-
// The offset was already calculated.
|
|
374
|
+
syncStreamsWithSequenceNumber_() {
|
|
375
|
+
if (this.streamsSynced_) {
|
|
372
376
|
return;
|
|
373
377
|
}
|
|
374
378
|
|
|
375
|
-
|
|
376
|
-
|
|
379
|
+
// Sync using media sequence number. Find the highest starting sequence
|
|
380
|
+
// number among all streams. Later, we will drop any references to
|
|
381
|
+
// earlier segments in other streams, then offset everything back to 0.
|
|
382
|
+
let highestStartingSequenceNumber = -1;
|
|
383
|
+
const firstSequenceNumberMap = new Map();
|
|
384
|
+
|
|
377
385
|
for (const streamInfo of this.uriToStreamInfosMap_.values()) {
|
|
378
386
|
const segmentIndex = streamInfo.stream.segmentIndex;
|
|
379
387
|
if (segmentIndex) {
|
|
380
|
-
segmentIndex.
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
388
|
+
const segment0 = segmentIndex.earliestReference();
|
|
389
|
+
if (segment0) {
|
|
390
|
+
// This looks inefficient, but iteration order is insertion order.
|
|
391
|
+
// So the very first entry should be the one we want.
|
|
392
|
+
// We assert that this holds true so that we are alerted by debug
|
|
393
|
+
// builds and tests if it changes. We still do a loop, though, so
|
|
394
|
+
// that the code functions correctly in production no matter what.
|
|
395
|
+
if (goog.DEBUG) {
|
|
396
|
+
const firstSequenceStartTime =
|
|
397
|
+
streamInfo.mediaSequenceToStartTime.values().next().value;
|
|
398
|
+
goog.asserts.assert(
|
|
399
|
+
firstSequenceStartTime == segment0.startTime,
|
|
400
|
+
'Sequence number map is not ordered as expected!');
|
|
384
401
|
}
|
|
385
|
-
|
|
402
|
+
for (const [sequence, start] of streamInfo.mediaSequenceToStartTime) {
|
|
403
|
+
if (start == segment0.startTime) {
|
|
404
|
+
firstSequenceNumberMap.set(streamInfo, sequence);
|
|
405
|
+
|
|
406
|
+
highestStartingSequenceNumber = Math.max(
|
|
407
|
+
highestStartingSequenceNumber, sequence);
|
|
408
|
+
break;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
386
412
|
}
|
|
387
413
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
414
|
+
|
|
415
|
+
if (highestStartingSequenceNumber < 0) {
|
|
416
|
+
// Nothing to sync.
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// From now on, updates will ignore any references before this number.
|
|
421
|
+
this.minSequenceNumber_ = highestStartingSequenceNumber;
|
|
422
|
+
|
|
423
|
+
shaka.log.debug('Syncing HLS streams against base sequence number:',
|
|
424
|
+
this.minSequenceNumber_);
|
|
425
|
+
|
|
426
|
+
for (const streamInfo of this.uriToStreamInfosMap_.values()) {
|
|
427
|
+
const segmentIndex = streamInfo.stream.segmentIndex;
|
|
428
|
+
if (segmentIndex) {
|
|
429
|
+
// Drop any earlier references.
|
|
430
|
+
const numSegmentsToDrop = this.minSequenceNumber_ -
|
|
431
|
+
firstSequenceNumberMap.get(streamInfo);
|
|
432
|
+
segmentIndex.dropFirstReferences(numSegmentsToDrop);
|
|
433
|
+
|
|
434
|
+
// Now adjust timestamps back to begin at 0.
|
|
435
|
+
const segmentN = segmentIndex.earliestReference();
|
|
436
|
+
if (segmentN) {
|
|
437
|
+
this.offsetStream_(streamInfo, -segmentN.startTime);
|
|
394
438
|
}
|
|
395
439
|
}
|
|
396
440
|
}
|
|
441
|
+
|
|
442
|
+
this.streamsSynced_ = true;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Synchronize streams by the EXT-X-PROGRAM-DATE-TIME tags attached to their
|
|
447
|
+
* segments. Also normalizes segment times so that the earliest segment in
|
|
448
|
+
* any stream is at time 0.
|
|
449
|
+
* @private
|
|
450
|
+
*/
|
|
451
|
+
syncStreamsWithProgramDateTime_() {
|
|
452
|
+
if (this.streamsSynced_) {
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
let lowestSyncTime = Infinity;
|
|
457
|
+
|
|
458
|
+
for (const streamInfo of this.uriToStreamInfosMap_.values()) {
|
|
459
|
+
const segmentIndex = streamInfo.stream.segmentIndex;
|
|
460
|
+
if (segmentIndex) {
|
|
461
|
+
const segment0 = segmentIndex.earliestReference();
|
|
462
|
+
if (segment0 != null && segment0.syncTime != null) {
|
|
463
|
+
lowestSyncTime = Math.min(lowestSyncTime, segment0.syncTime);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
if (lowestSyncTime == Infinity) {
|
|
469
|
+
// Nothing to sync.
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
shaka.log.debug('Syncing HLS streams against base time:', lowestSyncTime);
|
|
474
|
+
|
|
475
|
+
for (const streamInfo of this.uriToStreamInfosMap_.values()) {
|
|
476
|
+
const segmentIndex = streamInfo.stream.segmentIndex;
|
|
477
|
+
if (segmentIndex != null) {
|
|
478
|
+
const segment0 = segmentIndex.earliestReference();
|
|
479
|
+
if (segment0.syncTime == null) {
|
|
480
|
+
shaka.log.alwaysError('Missing EXT-X-PROGRAM-DATE-TIME for stream',
|
|
481
|
+
streamInfo.verbatimMediaPlaylistUri,
|
|
482
|
+
'Expect AV sync issues!');
|
|
483
|
+
} else {
|
|
484
|
+
// The first segment's target startTime should be based entirely on
|
|
485
|
+
// its syncTime. The rest of the stream will be based on that
|
|
486
|
+
// starting point. The earliest segment sync time from any stream
|
|
487
|
+
// will become presentation time 0. If two streams start e.g. 6
|
|
488
|
+
// seconds apart in syncTime, then their first segments will also
|
|
489
|
+
// start 6 seconds apart in presentation time.
|
|
490
|
+
const segment0TargetTime = segment0.syncTime - lowestSyncTime;
|
|
491
|
+
const streamOffset = segment0TargetTime - segment0.startTime;
|
|
492
|
+
|
|
493
|
+
this.offsetStream_(streamInfo, streamOffset);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
this.streamsSynced_ = true;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* @param {!shaka.hls.HlsParser.StreamInfo} streamInfo
|
|
503
|
+
* @param {number} offset
|
|
504
|
+
* @private
|
|
505
|
+
*/
|
|
506
|
+
offsetStream_(streamInfo, offset) {
|
|
507
|
+
streamInfo.stream.segmentIndex.offset(offset);
|
|
508
|
+
|
|
509
|
+
streamInfo.maxTimestamp += offset;
|
|
510
|
+
goog.asserts.assert(streamInfo.maxTimestamp >= 0,
|
|
511
|
+
'Negative maxTimestamp after adjustment!');
|
|
512
|
+
|
|
513
|
+
for (const [key, value] of streamInfo.mediaSequenceToStartTime) {
|
|
514
|
+
streamInfo.mediaSequenceToStartTime.set(key, value + offset);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
shaka.log.debug('Offset', offset, 'applied to',
|
|
518
|
+
streamInfo.verbatimMediaPlaylistUri);
|
|
397
519
|
}
|
|
398
520
|
|
|
399
521
|
/**
|
|
@@ -524,7 +646,11 @@ shaka.hls.HlsParser = class {
|
|
|
524
646
|
|
|
525
647
|
// Now that we have generated all streams, we can determine the offset to
|
|
526
648
|
// apply to sync times.
|
|
527
|
-
this.
|
|
649
|
+
if (this.config_.hls.ignoreManifestProgramDateTime) {
|
|
650
|
+
this.syncStreamsWithSequenceNumber_();
|
|
651
|
+
} else {
|
|
652
|
+
this.syncStreamsWithProgramDateTime_();
|
|
653
|
+
}
|
|
528
654
|
|
|
529
655
|
if (this.aesEncrypted_ && variants.length == 0) {
|
|
530
656
|
// We do not support AES-128 encryption with HLS yet. Variants is null
|
|
@@ -539,15 +665,12 @@ shaka.hls.HlsParser = class {
|
|
|
539
665
|
|
|
540
666
|
// Find the min and max timestamp of the earliest segment in all streams.
|
|
541
667
|
// Find the minimum duration of all streams as well.
|
|
542
|
-
let minFirstTimestamp = Infinity;
|
|
543
668
|
let minDuration = Infinity;
|
|
544
|
-
|
|
545
669
|
for (const streamInfo of this.uriToStreamInfosMap_.values()) {
|
|
546
|
-
minFirstTimestamp =
|
|
547
|
-
Math.min(minFirstTimestamp, streamInfo.minTimestamp);
|
|
548
670
|
if (streamInfo.stream.type != 'text') {
|
|
549
|
-
|
|
550
|
-
|
|
671
|
+
// Since everything is already offset to 0 (either by sync or by being
|
|
672
|
+
// VOD), only maxTimestamp is necessary to compute the duration.
|
|
673
|
+
minDuration = Math.min(minDuration, streamInfo.maxTimestamp);
|
|
551
674
|
}
|
|
552
675
|
}
|
|
553
676
|
|
|
@@ -591,18 +714,11 @@ shaka.hls.HlsParser = class {
|
|
|
591
714
|
segmentAvailabilityDuration);
|
|
592
715
|
}
|
|
593
716
|
} else {
|
|
594
|
-
// For VOD/EVENT content, offset everything back to 0.
|
|
595
|
-
// Use the minimum timestamp as the offset for all streams.
|
|
596
717
|
// Use the minimum duration as the presentation duration.
|
|
597
718
|
this.presentationTimeline_.setDuration(minDuration);
|
|
598
|
-
// Use a negative offset to adjust towards 0.
|
|
599
|
-
this.presentationTimeline_.offset(-minFirstTimestamp);
|
|
600
719
|
|
|
601
720
|
for (const streamInfo of this.uriToStreamInfosMap_.values()) {
|
|
602
|
-
//
|
|
603
|
-
// presentation-aligned times, so offset them all now.
|
|
604
|
-
streamInfo.stream.segmentIndex.offset(-minFirstTimestamp);
|
|
605
|
-
// Finally, fit the segments to the playlist duration.
|
|
721
|
+
// Fit the segments to the playlist duration.
|
|
606
722
|
streamInfo.stream.segmentIndex.fit(/* periodStart= */ 0, minDuration);
|
|
607
723
|
}
|
|
608
724
|
}
|
|
@@ -623,8 +739,14 @@ shaka.hls.HlsParser = class {
|
|
|
623
739
|
for (const stream of streamsToNotify) {
|
|
624
740
|
this.segmentsToNotifyByStream_.push(stream.segmentIndex.references);
|
|
625
741
|
}
|
|
742
|
+
|
|
626
743
|
this.notifySegments_();
|
|
627
744
|
|
|
745
|
+
// This is the first point where we have a meaningful presentation start
|
|
746
|
+
// time, and we need to tell PresentationTimeline that so that it can
|
|
747
|
+
// maintain consistency from here on.
|
|
748
|
+
this.presentationTimeline_.lockStartTime();
|
|
749
|
+
|
|
628
750
|
// This asserts that the live edge is being calculated from segment times.
|
|
629
751
|
// For VOD and event streams, this check should still pass.
|
|
630
752
|
goog.asserts.assert(
|
|
@@ -810,12 +932,7 @@ shaka.hls.HlsParser = class {
|
|
|
810
932
|
});
|
|
811
933
|
|
|
812
934
|
// Create stream info for each audio / video media tag.
|
|
813
|
-
|
|
814
|
-
// and can be reused.
|
|
815
|
-
if (mediaTags.length) {
|
|
816
|
-
await this.createStreamInfoFromMediaTag_(mediaTags[0]);
|
|
817
|
-
}
|
|
818
|
-
const promises = mediaTags.slice(1).map((tag) => {
|
|
935
|
+
const promises = mediaTags.map((tag) => {
|
|
819
936
|
return this.createStreamInfoFromMediaTag_(tag);
|
|
820
937
|
});
|
|
821
938
|
await Promise.all(promises);
|
|
@@ -1583,7 +1700,6 @@ shaka.hls.HlsParser = class {
|
|
|
1583
1700
|
throw error;
|
|
1584
1701
|
}
|
|
1585
1702
|
|
|
1586
|
-
const minTimestamp = segments[0].startTime;
|
|
1587
1703
|
const lastEndTime = segments[segments.length - 1].endTime;
|
|
1588
1704
|
/** @type {!shaka.media.SegmentIndex} */
|
|
1589
1705
|
const segmentIndex = new shaka.media.SegmentIndex(segments);
|
|
@@ -1641,7 +1757,6 @@ shaka.hls.HlsParser = class {
|
|
|
1641
1757
|
stream,
|
|
1642
1758
|
verbatimMediaPlaylistUri,
|
|
1643
1759
|
absoluteMediaPlaylistUri,
|
|
1644
|
-
minTimestamp,
|
|
1645
1760
|
maxTimestamp: lastEndTime,
|
|
1646
1761
|
mediaSequenceToStartTime,
|
|
1647
1762
|
canSkipSegments,
|
|
@@ -1749,8 +1864,6 @@ shaka.hls.HlsParser = class {
|
|
|
1749
1864
|
/* presentationStartTime= */ null, /* delay= */ 0);
|
|
1750
1865
|
this.presentationTimeline_.setStatic(true);
|
|
1751
1866
|
}
|
|
1752
|
-
|
|
1753
|
-
this.notifySegments_();
|
|
1754
1867
|
}
|
|
1755
1868
|
|
|
1756
1869
|
/**
|
|
@@ -1853,15 +1966,9 @@ shaka.hls.HlsParser = class {
|
|
|
1853
1966
|
const dateTimeTag =
|
|
1854
1967
|
shaka.hls.Utils.getFirstTagWithName(tags, 'EXT-X-PROGRAM-DATE-TIME');
|
|
1855
1968
|
if (dateTimeTag && dateTimeTag.value) {
|
|
1856
|
-
|
|
1857
|
-
goog.asserts.assert(
|
|
1969
|
+
syncTime = shaka.util.XmlUtils.parseDate(dateTimeTag.value);
|
|
1970
|
+
goog.asserts.assert(syncTime != null,
|
|
1858
1971
|
'EXT-X-PROGRAM-DATE-TIME format not valid');
|
|
1859
|
-
// Sync time offset is null on the first go-through. This indicates that
|
|
1860
|
-
// we have not yet seen every stream, and thus do not yet have enough
|
|
1861
|
-
// information to determine how to normalize the sync times.
|
|
1862
|
-
// For that first go-through, the sync time will be applied after the
|
|
1863
|
-
// references are all created. Until then, just offset by 0.
|
|
1864
|
-
syncTime = time + (this.syncTimeOffset_ || 0);
|
|
1865
1972
|
}
|
|
1866
1973
|
}
|
|
1867
1974
|
|
|
@@ -1892,9 +1999,20 @@ shaka.hls.HlsParser = class {
|
|
|
1892
1999
|
const pPreviousReference = i == 0 ?
|
|
1893
2000
|
previousReference : partialSegmentRefs[partialSegmentRefs.length - 1];
|
|
1894
2001
|
const pStartTime = (i == 0) ? startTime : pPreviousReference.endTime;
|
|
1895
|
-
|
|
1896
|
-
//
|
|
1897
|
-
//
|
|
2002
|
+
|
|
2003
|
+
// If DURATION is missing from this partial segment, use the target
|
|
2004
|
+
// partial duration from the top of the playlist, which is a required
|
|
2005
|
+
// attribute for content with partial segments.
|
|
2006
|
+
const pDuration = Number(item.getAttributeValue('DURATION')) ||
|
|
2007
|
+
this.partialTargetDuration_;
|
|
2008
|
+
|
|
2009
|
+
// If for some reason we have neither an explicit duration, nor a target
|
|
2010
|
+
// partial duration, we should SKIP this partial segment to avoid
|
|
2011
|
+
// duplicating content in the presentation timeline.
|
|
2012
|
+
if (!pDuration) {
|
|
2013
|
+
continue;
|
|
2014
|
+
}
|
|
2015
|
+
|
|
1898
2016
|
const pEndTime = pStartTime + pDuration;
|
|
1899
2017
|
|
|
1900
2018
|
let pStartByte = 0;
|
|
@@ -2074,16 +2192,13 @@ shaka.hls.HlsParser = class {
|
|
|
2074
2192
|
firstStartTime = mediaSequenceToStartTime.get(position);
|
|
2075
2193
|
}
|
|
2076
2194
|
|
|
2077
|
-
const firstSegmentUri = hlsSegments[0].absoluteUri;
|
|
2078
|
-
shaka.log.debug('First segment', firstSegmentUri.split('/').pop(),
|
|
2079
|
-
'starts at', firstStartTime);
|
|
2080
|
-
|
|
2081
2195
|
/** @type {!Array.<!shaka.media.SegmentReference>} */
|
|
2082
2196
|
const references = [];
|
|
2083
2197
|
|
|
2198
|
+
let previousReference = null;
|
|
2199
|
+
|
|
2084
2200
|
for (let i = 0; i < hlsSegments.length; i++) {
|
|
2085
2201
|
const item = hlsSegments[i];
|
|
2086
|
-
const previousReference = references[references.length - 1];
|
|
2087
2202
|
const startTime =
|
|
2088
2203
|
(i == 0) ? firstStartTime : previousReference.endTime;
|
|
2089
2204
|
position = mediaSequenceNumber + skippedSegments + i;
|
|
@@ -2113,9 +2228,17 @@ shaka.hls.HlsParser = class {
|
|
|
2113
2228
|
variables,
|
|
2114
2229
|
playlist.absoluteUri,
|
|
2115
2230
|
type);
|
|
2231
|
+
previousReference = reference;
|
|
2116
2232
|
|
|
2117
2233
|
if (reference) {
|
|
2118
|
-
|
|
2234
|
+
if (this.config_.hls.ignoreManifestProgramDateTime &&
|
|
2235
|
+
this.minSequenceNumber_ != null &&
|
|
2236
|
+
position < this.minSequenceNumber_) {
|
|
2237
|
+
// This segment is ignored as part of our fallback synchronization
|
|
2238
|
+
// method.
|
|
2239
|
+
} else {
|
|
2240
|
+
references.push(reference);
|
|
2241
|
+
}
|
|
2119
2242
|
}
|
|
2120
2243
|
}
|
|
2121
2244
|
|
|
@@ -2245,12 +2368,16 @@ shaka.hls.HlsParser = class {
|
|
|
2245
2368
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
2246
2369
|
const requestType = shaka.net.NetworkingEngine.RequestType.SEGMENT;
|
|
2247
2370
|
|
|
2371
|
+
// If you wait long enough, requesting the first segment can fail
|
|
2372
|
+
// because it has fallen off the left edge of DVR, so to be safer,
|
|
2373
|
+
// let's request the middle segment.
|
|
2248
2374
|
goog.asserts.assert(playlist.segments.length,
|
|
2249
2375
|
'Playlist should have segments!');
|
|
2250
|
-
const
|
|
2251
|
-
|
|
2376
|
+
const middleSegmentIdx = Math.trunc((playlist.segments.length - 1) / 2);
|
|
2377
|
+
const middleSegmentUri = this.variableSubstitution_(
|
|
2378
|
+
playlist.segments[middleSegmentIdx].absoluteUri, variables);
|
|
2252
2379
|
|
|
2253
|
-
const parsedUri = new goog.Uri(
|
|
2380
|
+
const parsedUri = new goog.Uri(middleSegmentUri);
|
|
2254
2381
|
const extension = parsedUri.getPath().split('.').pop();
|
|
2255
2382
|
const map = HlsParser.EXTENSION_MAP_BY_CONTENT_TYPE_[contentType];
|
|
2256
2383
|
|
|
@@ -2280,7 +2407,7 @@ shaka.hls.HlsParser = class {
|
|
|
2280
2407
|
// If unable to guess mime type, request a segment and try getting it
|
|
2281
2408
|
// from the response.
|
|
2282
2409
|
const headRequest = shaka.net.NetworkingEngine.makeRequest(
|
|
2283
|
-
[
|
|
2410
|
+
[middleSegmentUri], this.config_.retryParameters);
|
|
2284
2411
|
headRequest.method = 'HEAD';
|
|
2285
2412
|
|
|
2286
2413
|
const response = await this.makeNetworkRequest_(
|
|
@@ -2567,7 +2694,6 @@ shaka.hls.HlsParser = class {
|
|
|
2567
2694
|
* stream: !shaka.extern.Stream,
|
|
2568
2695
|
* verbatimMediaPlaylistUri: string,
|
|
2569
2696
|
* absoluteMediaPlaylistUri: string,
|
|
2570
|
-
* minTimestamp: number,
|
|
2571
2697
|
* maxTimestamp: number,
|
|
2572
2698
|
* mediaSequenceToStartTime: !Map.<number, number>,
|
|
2573
2699
|
* canSkipSegments: boolean
|
|
@@ -2586,8 +2712,6 @@ shaka.hls.HlsParser = class {
|
|
|
2586
2712
|
* @property {string} absoluteMediaPlaylistUri
|
|
2587
2713
|
* The absolute media playlist URI, resolved relative to the master playlist
|
|
2588
2714
|
* and updated to reflect any redirects.
|
|
2589
|
-
* @property {number} minTimestamp
|
|
2590
|
-
* The minimum timestamp found in the stream.
|
|
2591
2715
|
* @property {number} maxTimestamp
|
|
2592
2716
|
* The maximum timestamp found in the stream.
|
|
2593
2717
|
* @property {!Map.<number, number>} mediaSequenceToStartTime
|
package/lib/media/drm_engine.js
CHANGED
|
@@ -1424,6 +1424,9 @@ shaka.media.DrmEngine = class {
|
|
|
1424
1424
|
}
|
|
1425
1425
|
return;
|
|
1426
1426
|
}
|
|
1427
|
+
if (this.destroyer_.destroyed()) {
|
|
1428
|
+
return;
|
|
1429
|
+
}
|
|
1427
1430
|
|
|
1428
1431
|
const updateEvent = new shaka.util.FakeEvent('drmsessionupdate');
|
|
1429
1432
|
this.playerInterface_.onEvent(updateEvent);
|