shaka-player 4.2.11 → 4.2.13
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/ISSUE_TEMPLATE/bug_report.md +11 -0
- package/.github/workflows/appspot.yaml +39 -0
- package/.github/workflows/build-and-test.yaml +15 -0
- package/.github/workflows/selenium-lab-tests.yaml +3 -2
- package/.github/workflows/update-issues.yaml +1 -0
- package/CHANGELOG.md +42 -0
- package/CONTRIBUTORS +1 -0
- package/demo/custom.js +1 -1
- package/dist/demo.compiled.debug.js +2 -2
- package/dist/demo.compiled.debug.map +2 -2
- package/dist/demo.compiled.js +2 -2
- package/dist/demo.compiled.map +2 -2
- package/dist/deps.js +3 -3
- package/dist/locales.js +33 -33
- package/dist/shaka-player.compiled.d.ts +22 -0
- package/dist/shaka-player.compiled.debug.d.ts +22 -0
- package/dist/shaka-player.compiled.debug.js +233 -232
- package/dist/shaka-player.compiled.debug.map +3 -3
- package/dist/shaka-player.compiled.js +738 -738
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.d.ts +22 -0
- package/dist/shaka-player.ui.debug.d.ts +22 -0
- package/dist/shaka-player.ui.debug.js +259 -258
- package/dist/shaka-player.ui.debug.map +3 -3
- package/dist/shaka-player.ui.js +917 -916
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/drm-config.md +9 -6
- package/docs/tutorials/selenium-grid-config.md +60 -8
- package/externs/ima.js +34 -0
- package/karma.conf.js +50 -7
- package/lib/abr/simple_abr_manager.js +6 -6
- package/lib/cea/mp4_cea_parser.js +30 -14
- package/lib/dash/dash_parser.js +18 -3
- package/lib/hls/hls_parser.js +13 -2
- package/lib/media/drm_engine.js +14 -8
- package/lib/media/gap_jumping_controller.js +24 -2
- package/lib/media/media_source_engine.js +5 -3
- package/lib/media/playhead.js +11 -0
- package/lib/media/region_observer.js +19 -1
- package/lib/media/streaming_engine.js +7 -3
- package/lib/media/video_wrapper.js +6 -1
- package/lib/player.js +9 -8
- package/lib/polyfill/abort_controller.js +7 -0
- package/lib/polyfill/orientation.js +34 -7
- package/lib/text/vtt_text_parser.js +3 -1
- package/lib/util/manifest_parser_utils.js +5 -3
- package/lib/util/mp4_box_parsers.js +8 -3
- package/lib/util/platform.js +14 -0
- package/lib/util/stream_utils.js +70 -26
- package/package.json +2 -3
- package/test/cast/cast_utils_unit.js +4 -1
- package/test/cea/mp4_cea_parser_unit.js +26 -3
- package/test/dash/dash_parser_manifest_unit.js +120 -0
- package/test/hls/hls_parser_unit.js +222 -0
- package/test/media/drm_engine_integration.js +2 -2
- package/test/media/region_observer_unit.js +2 -1
- package/test/media/segment_index_unit.js +3 -3
- package/test/media/streaming_engine_integration.js +14 -11
- package/test/offline/offline_integration.js +6 -3
- package/test/player_external.js +19 -16
- package/test/player_integration.js +35 -48
- package/test/player_src_equals_integration.js +9 -5
- package/test/test/assets/multiple-trun-init.mp4 +0 -0
- package/test/test/assets/multiple-trun-segment.mp4 +0 -0
- package/test/test/util/fake_demo_main.js +7 -3
- package/test/test/util/layout_tests.js +2 -2
- package/test/test/util/ui_utils.js +9 -2
- package/test/test/util/util.js +6 -27
- package/test/test/util/waiter.js +73 -3
- package/test/ui/ad_ui_unit.js +9 -9
- package/test/util/stream_utils_unit.js +46 -0
- package/ui/range_element.js +5 -0
- package/ui/resolution_selection.js +7 -1
package/lib/media/playhead.js
CHANGED
|
@@ -251,6 +251,7 @@ shaka.media.MediaSourcePlayhead = class {
|
|
|
251
251
|
this.videoWrapper_ = new shaka.media.VideoWrapper(
|
|
252
252
|
mediaElement,
|
|
253
253
|
() => this.onSeeking_(),
|
|
254
|
+
(realStartTime) => this.onStarted_(realStartTime),
|
|
254
255
|
this.getStartTime_(startTime));
|
|
255
256
|
|
|
256
257
|
/** @type {shaka.util.Timer} */
|
|
@@ -390,6 +391,16 @@ shaka.media.MediaSourcePlayhead = class {
|
|
|
390
391
|
}
|
|
391
392
|
}
|
|
392
393
|
|
|
394
|
+
/**
|
|
395
|
+
* Called when the video element has started up and is listening for new seeks
|
|
396
|
+
*
|
|
397
|
+
* @param {number} startTime
|
|
398
|
+
* @private
|
|
399
|
+
*/
|
|
400
|
+
onStarted_(startTime) {
|
|
401
|
+
this.gapController_.onStarted(startTime);
|
|
402
|
+
}
|
|
403
|
+
|
|
393
404
|
/**
|
|
394
405
|
* Handles when a seek happens on the video.
|
|
395
406
|
*
|
|
@@ -27,13 +27,24 @@ shaka.media.RegionObserver = class extends shaka.util.FakeEventTarget {
|
|
|
27
27
|
* destroy the timeline.
|
|
28
28
|
*
|
|
29
29
|
* @param {!shaka.media.RegionTimeline} timeline
|
|
30
|
+
* @param {boolean} startsPastZero
|
|
30
31
|
*/
|
|
31
|
-
constructor(timeline) {
|
|
32
|
+
constructor(timeline, startsPastZero) {
|
|
32
33
|
super();
|
|
33
34
|
|
|
34
35
|
/** @private {shaka.media.RegionTimeline} */
|
|
35
36
|
this.timeline_ = timeline;
|
|
36
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Whether the asset is expected to start at a time beyond 0 seconds.
|
|
40
|
+
* For example, if the asset is a live stream.
|
|
41
|
+
* If true, we will not start polling for regions until the playhead has
|
|
42
|
+
* moved past 0 seconds, to avoid bad behaviors where the current time is
|
|
43
|
+
* briefly 0 before we have enough data to play.
|
|
44
|
+
* @private {boolean}
|
|
45
|
+
*/
|
|
46
|
+
this.startsPastZero_ = startsPastZero;
|
|
47
|
+
|
|
37
48
|
/**
|
|
38
49
|
* A mapping between a region and where we previously were relative to it.
|
|
39
50
|
* When the value here differs from what we calculate, it means we moved and
|
|
@@ -121,6 +132,13 @@ shaka.media.RegionObserver = class extends shaka.util.FakeEventTarget {
|
|
|
121
132
|
/** @override */
|
|
122
133
|
poll(positionInSeconds, wasSeeking) {
|
|
123
134
|
const RegionObserver = shaka.media.RegionObserver;
|
|
135
|
+
if (this.startsPastZero_ && positionInSeconds == 0) {
|
|
136
|
+
// Don't start checking regions until the timeline has begun moving.
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
// Now that we have seen the playhead go past 0, it's okay if it goes
|
|
140
|
+
// back there (e.g. seeking back to the start).
|
|
141
|
+
this.startsPastZero_ = false;
|
|
124
142
|
|
|
125
143
|
for (const region of this.timeline_.regions()) {
|
|
126
144
|
const previousPosition = this.oldPosition_.get(region);
|
|
@@ -1308,7 +1308,8 @@ shaka.media.StreamingEngine = class {
|
|
|
1308
1308
|
const dataToAppend = remaining.subarray(0, offset);
|
|
1309
1309
|
remaining = remaining.subarray(offset);
|
|
1310
1310
|
await this.append_(
|
|
1311
|
-
mediaState, presentationTime, stream, reference, dataToAppend
|
|
1311
|
+
mediaState, presentationTime, stream, reference, dataToAppend,
|
|
1312
|
+
/* isChunkedData= */ true);
|
|
1312
1313
|
}
|
|
1313
1314
|
};
|
|
1314
1315
|
|
|
@@ -1696,10 +1697,12 @@ shaka.media.StreamingEngine = class {
|
|
|
1696
1697
|
* @param {shaka.extern.Stream} stream
|
|
1697
1698
|
* @param {!shaka.media.SegmentReference} reference
|
|
1698
1699
|
* @param {BufferSource} segment
|
|
1700
|
+
* @param {boolean=} isChunkedData
|
|
1699
1701
|
* @return {!Promise}
|
|
1700
1702
|
* @private
|
|
1701
1703
|
*/
|
|
1702
|
-
async append_(mediaState, presentationTime, stream, reference, segment
|
|
1704
|
+
async append_(mediaState, presentationTime, stream, reference, segment,
|
|
1705
|
+
isChunkedData = false) {
|
|
1703
1706
|
const logPrefix = shaka.media.StreamingEngine.logPrefix_(mediaState);
|
|
1704
1707
|
|
|
1705
1708
|
const hasClosedCaptions = stream.closedCaptions &&
|
|
@@ -1732,7 +1735,8 @@ shaka.media.StreamingEngine = class {
|
|
|
1732
1735
|
reference,
|
|
1733
1736
|
hasClosedCaptions,
|
|
1734
1737
|
seeked,
|
|
1735
|
-
adaptation
|
|
1738
|
+
adaptation,
|
|
1739
|
+
isChunkedData);
|
|
1736
1740
|
this.destroyer_.ensureNotDestroyed();
|
|
1737
1741
|
shaka.log.v2(logPrefix, 'appended media segment');
|
|
1738
1742
|
}
|
|
@@ -27,15 +27,19 @@ shaka.media.VideoWrapper = class {
|
|
|
27
27
|
/**
|
|
28
28
|
* @param {!HTMLMediaElement} video
|
|
29
29
|
* @param {function()} onSeek Called when the video seeks.
|
|
30
|
+
* @param {function(number)} onStarted Called when the video has started.
|
|
30
31
|
* @param {number} startTime The time to start at.
|
|
31
32
|
*/
|
|
32
|
-
constructor(video, onSeek, startTime) {
|
|
33
|
+
constructor(video, onSeek, onStarted, startTime) {
|
|
33
34
|
/** @private {HTMLMediaElement} */
|
|
34
35
|
this.video_ = video;
|
|
35
36
|
|
|
36
37
|
/** @private {function()} */
|
|
37
38
|
this.onSeek_ = onSeek;
|
|
38
39
|
|
|
40
|
+
/** @private {function(number)} */
|
|
41
|
+
this.onStarted_ = onStarted;
|
|
42
|
+
|
|
39
43
|
/** @private {number} */
|
|
40
44
|
this.startTime_ = startTime;
|
|
41
45
|
|
|
@@ -165,6 +169,7 @@ shaka.media.VideoWrapper = class {
|
|
|
165
169
|
this.started_ = true;
|
|
166
170
|
|
|
167
171
|
this.eventManager_.listen(this.video_, 'seeking', () => this.onSeek_());
|
|
172
|
+
this.onStarted_(this.video_.currentTime);
|
|
168
173
|
}
|
|
169
174
|
};
|
|
170
175
|
|
package/lib/player.js
CHANGED
|
@@ -1996,7 +1996,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
1996
1996
|
this.abrManager_.setMediaElement(mediaElement);
|
|
1997
1997
|
|
|
1998
1998
|
this.playhead_ = this.createPlayhead(has.startTime);
|
|
1999
|
-
this.playheadObservers_ =
|
|
1999
|
+
this.playheadObservers_ =
|
|
2000
|
+
this.createPlayheadObserversForMSE_(has.startTimeOfLoad);
|
|
2000
2001
|
|
|
2001
2002
|
// We need to start the buffer management code near the end because it will
|
|
2002
2003
|
// set the initial buffering state and that depends on other components
|
|
@@ -2068,10 +2069,6 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2068
2069
|
|
|
2069
2070
|
this.playhead_.setStartTime(adjustedTime);
|
|
2070
2071
|
}
|
|
2071
|
-
|
|
2072
|
-
// Since the first streams just became active, send an adaptation event.
|
|
2073
|
-
this.onAdaptation_(null,
|
|
2074
|
-
shaka.util.StreamUtils.variantToTrack(initialVariant));
|
|
2075
2072
|
}
|
|
2076
2073
|
|
|
2077
2074
|
this.playhead_.ready();
|
|
@@ -2761,17 +2758,21 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
|
|
|
2761
2758
|
* Create the observers for MSE playback. These observers are responsible for
|
|
2762
2759
|
* notifying the app and player of specific events during MSE playback.
|
|
2763
2760
|
*
|
|
2761
|
+
* @param {number} startTimeOfLoad
|
|
2764
2762
|
* @return {!shaka.media.PlayheadObserverManager}
|
|
2765
2763
|
* @private
|
|
2766
2764
|
*/
|
|
2767
|
-
createPlayheadObserversForMSE_() {
|
|
2765
|
+
createPlayheadObserversForMSE_(startTimeOfLoad) {
|
|
2768
2766
|
goog.asserts.assert(this.manifest_, 'Must have manifest');
|
|
2769
2767
|
goog.asserts.assert(this.regionTimeline_, 'Must have region timeline');
|
|
2770
2768
|
goog.asserts.assert(this.video_, 'Must have video element');
|
|
2771
2769
|
|
|
2770
|
+
const startsPastZero = this.isLive() || startTimeOfLoad > 0;
|
|
2771
|
+
|
|
2772
2772
|
// Create the region observer. This will allow us to notify the app when we
|
|
2773
2773
|
// move in and out of timeline regions.
|
|
2774
|
-
const regionObserver = new shaka.media.RegionObserver(
|
|
2774
|
+
const regionObserver = new shaka.media.RegionObserver(
|
|
2775
|
+
this.regionTimeline_, startsPastZero);
|
|
2775
2776
|
|
|
2776
2777
|
regionObserver.addEventListener('enter', (event) => {
|
|
2777
2778
|
/** @type {shaka.extern.TimelineRegionInfo} */
|
|
@@ -6630,7 +6631,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6630
6631
|
* @define {string} A version number taken from git at compile time.
|
|
6631
6632
|
* @export
|
|
6632
6633
|
*/
|
|
6633
|
-
shaka.Player.version = 'v4.2.
|
|
6634
|
+
shaka.Player.version = 'v4.2.13-uncompiled';
|
|
6634
6635
|
|
|
6635
6636
|
// Initialize the deprecation system using the version string we just set
|
|
6636
6637
|
// on the player.
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
goog.provide('shaka.polyfill.Orientation');
|
|
8
8
|
|
|
9
|
+
goog.require('shaka.log');
|
|
9
10
|
goog.require('shaka.util.FakeEvent');
|
|
10
11
|
goog.require('shaka.util.FakeEventTarget');
|
|
11
12
|
goog.require('shaka.polyfill');
|
|
@@ -23,21 +24,47 @@ shaka.polyfill.Orientation = class {
|
|
|
23
24
|
* @export
|
|
24
25
|
*/
|
|
25
26
|
static install() {
|
|
26
|
-
if (screen.orientation) {
|
|
27
|
+
if (screen.orientation && screen.orientation.unlock) {
|
|
27
28
|
// Not needed.
|
|
29
|
+
shaka.log.info('Using native screen.orientation');
|
|
28
30
|
return;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (window.orientation != undefined) {
|
|
33
|
+
if (screen.orientation != undefined) {
|
|
34
|
+
// There are some platforms where screen.orientation is defined but
|
|
35
|
+
// incomplete (e.g. Safari).
|
|
36
|
+
// Install a very simple polyfill in that case.
|
|
37
|
+
shaka.polyfill.Orientation.installBasedOnScreenMethods_();
|
|
38
|
+
} else if (window.orientation != undefined) {
|
|
39
|
+
// There is no way to check to see if the 'orientationchange' event exists
|
|
40
|
+
// on window, which could theoretically lead to this making a
|
|
41
|
+
// screen.orientation object that doesn't actually work.
|
|
42
|
+
// However, it looks like all platforms that support the deprecated
|
|
43
|
+
// window.orientation feature also support that event.
|
|
37
44
|
shaka.polyfill.Orientation.installBasedOnWindowMethods_();
|
|
38
45
|
}
|
|
39
46
|
}
|
|
40
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Modifies screen.orientation to add no-ops for missing methods.
|
|
50
|
+
* Meant for cases where screen.orientation is defined, but has missing
|
|
51
|
+
* methods that cannot be properly polyfilled.
|
|
52
|
+
* @private
|
|
53
|
+
*/
|
|
54
|
+
static installBasedOnScreenMethods_() {
|
|
55
|
+
if (screen.orientation.lock === undefined) {
|
|
56
|
+
screen.orientation.lock = (orientation) => {
|
|
57
|
+
shaka.log.info('screen.orientation.lock is a no-op');
|
|
58
|
+
return Promise.resolve();
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (screen.orientation.unlock === undefined) {
|
|
62
|
+
screen.orientation.unlock = () => {
|
|
63
|
+
shaka.log.info('screen.orientation.unlock is a no-op');
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
41
68
|
/**
|
|
42
69
|
* Makes a polyfill for orientation, based on window methods.
|
|
43
70
|
* Note that some of the features this is based on are deprecated, so this
|
|
@@ -674,6 +674,7 @@ shaka.text.VttTextParser = class {
|
|
|
674
674
|
cue.fontWeight = refCue.fontWeight;
|
|
675
675
|
cue.fontStyle = refCue.fontStyle;
|
|
676
676
|
cue.opacity = refCue.opacity;
|
|
677
|
+
cue.textShadow = refCue.textShadow;
|
|
677
678
|
cue.wrapLine = refCue.wrapLine;
|
|
678
679
|
}
|
|
679
680
|
|
|
@@ -785,7 +786,8 @@ shaka.text.VttTextParser = class {
|
|
|
785
786
|
} else if ((results = /^size:([\d.]+)%$/.exec(word))) {
|
|
786
787
|
cue.size = Number(results[1]);
|
|
787
788
|
} else if ((results =
|
|
788
|
-
|
|
789
|
+
// eslint-disable-next-line max-len
|
|
790
|
+
/^position:([\d.]+)%(?:,(line-left|line-right|middle|center|start|end))?$/
|
|
789
791
|
.exec(word))) {
|
|
790
792
|
cue.position = Number(results[1]);
|
|
791
793
|
if (results[2]) {
|
|
@@ -168,7 +168,7 @@ shaka.util.ManifestParserUtils.VIDEO_CODEC_REGEXPS_ = [
|
|
|
168
168
|
/^hvc/,
|
|
169
169
|
/^vp0?[89]/,
|
|
170
170
|
/^av01/,
|
|
171
|
-
/^
|
|
171
|
+
/^dvh/,
|
|
172
172
|
];
|
|
173
173
|
|
|
174
174
|
|
|
@@ -180,8 +180,10 @@ shaka.util.ManifestParserUtils.VIDEO_CODEC_REGEXPS_ = [
|
|
|
180
180
|
*/
|
|
181
181
|
shaka.util.ManifestParserUtils.AUDIO_CODEC_REGEXPS_ = [
|
|
182
182
|
/^vorbis$/,
|
|
183
|
-
/^
|
|
184
|
-
/^
|
|
183
|
+
/^Opus$/, // correct codec string according to RFC 6381 section 3.3
|
|
184
|
+
/^opus$/, // some manifests wrongfully use this
|
|
185
|
+
/^fLaC$/, // correct codec string according to RFC 6381 section 3.3
|
|
186
|
+
/^flac$/, // some manifests wrongfully use this
|
|
185
187
|
/^mp4a/,
|
|
186
188
|
/^[ae]c-3$/,
|
|
187
189
|
/^ac-4$/,
|
|
@@ -112,10 +112,11 @@ shaka.util.Mp4BoxParsers = class {
|
|
|
112
112
|
static parseTRUN(reader, version, flags) {
|
|
113
113
|
const sampleCount = reader.readUint32();
|
|
114
114
|
const sampleData = [];
|
|
115
|
+
let dataOffset = null;
|
|
115
116
|
|
|
116
|
-
//
|
|
117
|
+
// "data_offset"
|
|
117
118
|
if (flags & 0x000001) {
|
|
118
|
-
reader.
|
|
119
|
+
dataOffset = reader.readUint32();
|
|
119
120
|
}
|
|
120
121
|
|
|
121
122
|
// Skip "first_sample_flags" if present.
|
|
@@ -159,6 +160,7 @@ shaka.util.Mp4BoxParsers = class {
|
|
|
159
160
|
return {
|
|
160
161
|
sampleCount,
|
|
161
162
|
sampleData,
|
|
163
|
+
dataOffset,
|
|
162
164
|
};
|
|
163
165
|
}
|
|
164
166
|
|
|
@@ -252,13 +254,16 @@ shaka.util.ParsedTREXBox;
|
|
|
252
254
|
/**
|
|
253
255
|
* @typedef {{
|
|
254
256
|
* sampleCount: number,
|
|
255
|
-
* sampleData: !Array.<shaka.util.ParsedTRUNSample
|
|
257
|
+
* sampleData: !Array.<shaka.util.ParsedTRUNSample>,
|
|
258
|
+
* dataOffset: ?number
|
|
256
259
|
* }}
|
|
257
260
|
*
|
|
258
261
|
* @property {number} sampleCount
|
|
259
262
|
* As per the spec: the number of samples being added in this run;
|
|
260
263
|
* @property {!Array.<shaka.util.ParsedTRUNSample>} sampleData
|
|
261
264
|
* An array of size <sampleCount> containing data for each sample
|
|
265
|
+
* @property {?number} dataOffset
|
|
266
|
+
* If specified via flags, this indicate the offset of the sample in bytes.
|
|
262
267
|
*
|
|
263
268
|
* @exportDoc
|
|
264
269
|
*/
|
package/lib/util/platform.js
CHANGED
|
@@ -346,6 +346,20 @@ shaka.util.Platform = class {
|
|
|
346
346
|
return shaka.util.Platform.isApple() && navigator.maxTouchPoints > 1;
|
|
347
347
|
}
|
|
348
348
|
|
|
349
|
+
/**
|
|
350
|
+
* Return true if the platform is a Mac, regardless of the browser.
|
|
351
|
+
*
|
|
352
|
+
* @return {boolean}
|
|
353
|
+
*/
|
|
354
|
+
static isMac() {
|
|
355
|
+
// Try the newer standard first.
|
|
356
|
+
if (navigator.userAgentData && navigator.userAgentData.platform) {
|
|
357
|
+
return navigator.userAgentData.platform.toLowerCase() == 'macos';
|
|
358
|
+
}
|
|
359
|
+
// Fall back to the old API, with less strict matching.
|
|
360
|
+
return navigator.platform.toLowerCase().includes('mac');
|
|
361
|
+
}
|
|
362
|
+
|
|
349
363
|
/**
|
|
350
364
|
* Check if the user agent contains a key. This is the best way we know of
|
|
351
365
|
* right now to detect platforms. If there is a better way, please send a
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -436,47 +436,61 @@ shaka.util.StreamUtils = class {
|
|
|
436
436
|
manifest.variants = manifest.variants.filter((variant) => {
|
|
437
437
|
// See: https://github.com/shaka-project/shaka-player/issues/3860
|
|
438
438
|
const video = variant.video;
|
|
439
|
+
|
|
439
440
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
441
|
+
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
442
|
+
const MimeUtils = shaka.util.MimeUtils;
|
|
443
|
+
const StreamUtils = shaka.util.StreamUtils;
|
|
444
|
+
|
|
440
445
|
if (video) {
|
|
441
|
-
let videoCodecs =
|
|
442
|
-
|
|
446
|
+
let videoCodecs = StreamUtils.getCorrectVideoCodecs_(video.codecs);
|
|
447
|
+
|
|
443
448
|
// For multiplexed streams. Here we must check the audio of the
|
|
444
449
|
// stream to see if it is compatible.
|
|
445
450
|
if (video.codecs.includes(',')) {
|
|
446
451
|
const allCodecs = video.codecs.split(',');
|
|
447
|
-
|
|
452
|
+
|
|
453
|
+
videoCodecs = ManifestParserUtils.guessCodecs(
|
|
448
454
|
ContentType.VIDEO, allCodecs);
|
|
449
|
-
videoCodecs =
|
|
450
|
-
|
|
451
|
-
let audioCodecs =
|
|
455
|
+
videoCodecs = StreamUtils.getCorrectVideoCodecs_(videoCodecs);
|
|
456
|
+
|
|
457
|
+
let audioCodecs = ManifestParserUtils.guessCodecs(
|
|
452
458
|
ContentType.AUDIO, allCodecs);
|
|
453
|
-
audioCodecs =
|
|
454
|
-
|
|
455
|
-
const audioFullType =
|
|
459
|
+
audioCodecs = StreamUtils.getCorrectAudioCodecs_(audioCodecs);
|
|
460
|
+
|
|
461
|
+
const audioFullType = MimeUtils.getFullOrConvertedType(
|
|
456
462
|
video.mimeType, audioCodecs, ContentType.AUDIO);
|
|
463
|
+
|
|
457
464
|
if (!MediaSource.isTypeSupported(audioFullType)) {
|
|
458
465
|
return false;
|
|
459
466
|
}
|
|
467
|
+
|
|
460
468
|
// Update the codec string with the (possibly) converted codecs.
|
|
461
469
|
videoCodecs = [videoCodecs, audioCodecs].join(',');
|
|
462
470
|
}
|
|
463
|
-
|
|
471
|
+
|
|
472
|
+
const fullType = MimeUtils.getFullOrConvertedType(
|
|
464
473
|
video.mimeType, videoCodecs, ContentType.VIDEO);
|
|
474
|
+
|
|
465
475
|
if (!MediaSource.isTypeSupported(fullType)) {
|
|
466
476
|
return false;
|
|
467
477
|
}
|
|
478
|
+
|
|
468
479
|
// Update the codec string with the (possibly) converted codecs.
|
|
469
480
|
video.codecs = videoCodecs;
|
|
470
481
|
}
|
|
482
|
+
|
|
471
483
|
const audio = variant.audio;
|
|
484
|
+
|
|
472
485
|
if (audio) {
|
|
473
|
-
const codecs =
|
|
474
|
-
|
|
475
|
-
const fullType = shaka.util.MimeUtils.getFullOrConvertedType(
|
|
486
|
+
const codecs = StreamUtils.getCorrectAudioCodecs_(audio.codecs);
|
|
487
|
+
const fullType = MimeUtils.getFullOrConvertedType(
|
|
476
488
|
audio.mimeType, codecs, ContentType.AUDIO);
|
|
489
|
+
|
|
477
490
|
if (!MediaSource.isTypeSupported(fullType)) {
|
|
478
491
|
return false;
|
|
479
492
|
}
|
|
493
|
+
|
|
480
494
|
// Update the codec string with the (possibly) converted codecs.
|
|
481
495
|
audio.codecs = codecs;
|
|
482
496
|
}
|
|
@@ -488,7 +502,7 @@ shaka.util.StreamUtils = class {
|
|
|
488
502
|
(video.codecs.includes('avc1.') ||
|
|
489
503
|
video.codecs.includes('avc3.'))) {
|
|
490
504
|
shaka.log.debug('Dropping variant - not compatible with platform',
|
|
491
|
-
|
|
505
|
+
StreamUtils.getVariantSummaryString_(variant));
|
|
492
506
|
return false;
|
|
493
507
|
}
|
|
494
508
|
|
|
@@ -498,7 +512,7 @@ shaka.util.StreamUtils = class {
|
|
|
498
512
|
// Filter out all unsupported variants.
|
|
499
513
|
if (!supported) {
|
|
500
514
|
shaka.log.debug('Dropping variant - not compatible with platform',
|
|
501
|
-
|
|
515
|
+
StreamUtils.getVariantSummaryString_(variant));
|
|
502
516
|
}
|
|
503
517
|
return supported;
|
|
504
518
|
});
|
|
@@ -562,7 +576,11 @@ shaka.util.StreamUtils = class {
|
|
|
562
576
|
static getDecodingConfigs_(variant, usePersistentLicenses, srcEquals) {
|
|
563
577
|
const audio = variant.audio;
|
|
564
578
|
const video = variant.video;
|
|
579
|
+
|
|
565
580
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
581
|
+
const ManifestParserUtils = shaka.util.ManifestParserUtils;
|
|
582
|
+
const MimeUtils = shaka.util.MimeUtils;
|
|
583
|
+
const StreamUtils = shaka.util.StreamUtils;
|
|
566
584
|
|
|
567
585
|
/** @type {!MediaDecodingConfiguration} */
|
|
568
586
|
const mediaDecodingConfig = {
|
|
@@ -571,19 +589,23 @@ shaka.util.StreamUtils = class {
|
|
|
571
589
|
|
|
572
590
|
if (video) {
|
|
573
591
|
let videoCodecs = video.codecs;
|
|
592
|
+
|
|
574
593
|
// For multiplexed streams with audio+video codecs, the config should have
|
|
575
594
|
// AudioConfiguration and VideoConfiguration.
|
|
576
595
|
if (video.codecs.includes(',')) {
|
|
577
596
|
const allCodecs = video.codecs.split(',');
|
|
578
|
-
|
|
597
|
+
|
|
598
|
+
videoCodecs = ManifestParserUtils.guessCodecs(
|
|
579
599
|
ContentType.VIDEO, allCodecs);
|
|
580
|
-
videoCodecs =
|
|
581
|
-
|
|
582
|
-
|
|
600
|
+
videoCodecs = StreamUtils.getCorrectVideoCodecs_(videoCodecs);
|
|
601
|
+
|
|
602
|
+
let audioCodecs = ManifestParserUtils.guessCodecs(
|
|
583
603
|
ContentType.AUDIO, allCodecs);
|
|
604
|
+
audioCodecs = StreamUtils.getCorrectAudioCodecs_(audioCodecs);
|
|
584
605
|
|
|
585
|
-
const audioFullType =
|
|
606
|
+
const audioFullType = MimeUtils.getFullOrConvertedType(
|
|
586
607
|
video.mimeType, audioCodecs, ContentType.AUDIO);
|
|
608
|
+
|
|
587
609
|
mediaDecodingConfig.audio = {
|
|
588
610
|
contentType: audioFullType,
|
|
589
611
|
channels: 2,
|
|
@@ -592,9 +614,11 @@ shaka.util.StreamUtils = class {
|
|
|
592
614
|
spatialRendering: false,
|
|
593
615
|
};
|
|
594
616
|
}
|
|
595
|
-
|
|
596
|
-
|
|
617
|
+
|
|
618
|
+
videoCodecs = StreamUtils.getCorrectVideoCodecs_(videoCodecs);
|
|
619
|
+
const fullType = MimeUtils.getFullOrConvertedType(
|
|
597
620
|
video.mimeType, videoCodecs, ContentType.VIDEO);
|
|
621
|
+
|
|
598
622
|
// VideoConfiguration
|
|
599
623
|
mediaDecodingConfig.video = {
|
|
600
624
|
contentType: fullType,
|
|
@@ -627,9 +651,8 @@ shaka.util.StreamUtils = class {
|
|
|
627
651
|
}
|
|
628
652
|
}
|
|
629
653
|
if (audio) {
|
|
630
|
-
const codecs =
|
|
631
|
-
|
|
632
|
-
const fullType = shaka.util.MimeUtils.getFullOrConvertedType(
|
|
654
|
+
const codecs = StreamUtils.getCorrectAudioCodecs_(audio.codecs);
|
|
655
|
+
const fullType = MimeUtils.getFullOrConvertedType(
|
|
633
656
|
audio.mimeType, codecs, ContentType.AUDIO);
|
|
634
657
|
|
|
635
658
|
// AudioConfiguration
|
|
@@ -760,6 +783,20 @@ shaka.util.StreamUtils = class {
|
|
|
760
783
|
* @private
|
|
761
784
|
*/
|
|
762
785
|
static getCorrectAudioCodecs_(codecs) {
|
|
786
|
+
// According to RFC 6381 section 3.3, 'fLaC' is actually the correct
|
|
787
|
+
// codec string. We still need to map it to 'flac', as some browsers
|
|
788
|
+
// currently don't support 'fLaC', while 'flac' is supported by most
|
|
789
|
+
// major browsers.
|
|
790
|
+
// See https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
|
|
791
|
+
if (codecs === 'fLaC') {
|
|
792
|
+
return 'flac';
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// The same is true for 'Opus'.
|
|
796
|
+
if (codecs === 'Opus') {
|
|
797
|
+
return 'opus';
|
|
798
|
+
}
|
|
799
|
+
|
|
763
800
|
// Some Tizen devices seem to misreport AC-3 support, but correctly
|
|
764
801
|
// report EC-3 support. So query EC-3 as a fallback for AC-3.
|
|
765
802
|
// See https://github.com/shaka-project/shaka-player/issues/2989 for
|
|
@@ -1066,6 +1103,7 @@ shaka.util.StreamUtils = class {
|
|
|
1066
1103
|
track.frameRate = video.frameRate || null;
|
|
1067
1104
|
track.pixelAspectRatio = video.pixelAspectRatio || null;
|
|
1068
1105
|
track.videoBandwidth = video.bandwidth || null;
|
|
1106
|
+
track.hdr = video.hdr || null;
|
|
1069
1107
|
}
|
|
1070
1108
|
|
|
1071
1109
|
if (audio) {
|
|
@@ -1237,6 +1275,9 @@ shaka.util.StreamUtils = class {
|
|
|
1237
1275
|
if (textTrack.kind == 'captions') {
|
|
1238
1276
|
track.mimeType = CLOSED_CAPTION_MIMETYPE;
|
|
1239
1277
|
}
|
|
1278
|
+
if (textTrack.kind == 'subtitles') {
|
|
1279
|
+
track.mimeType = 'text/vtt';
|
|
1280
|
+
}
|
|
1240
1281
|
if (textTrack.kind) {
|
|
1241
1282
|
track.roles = [textTrack.kind];
|
|
1242
1283
|
}
|
|
@@ -1284,13 +1325,15 @@ shaka.util.StreamUtils = class {
|
|
|
1284
1325
|
* @private
|
|
1285
1326
|
*/
|
|
1286
1327
|
static html5TrackToGenericShakaTrack_(html5Track) {
|
|
1328
|
+
const language = html5Track.language;
|
|
1329
|
+
|
|
1287
1330
|
/** @type {shaka.extern.Track} */
|
|
1288
1331
|
const track = {
|
|
1289
1332
|
id: shaka.util.StreamUtils.html5TrackId(html5Track),
|
|
1290
1333
|
active: false,
|
|
1291
1334
|
type: '',
|
|
1292
1335
|
bandwidth: 0,
|
|
1293
|
-
language: shaka.util.LanguageUtils.normalize(
|
|
1336
|
+
language: shaka.util.LanguageUtils.normalize(language || 'und'),
|
|
1294
1337
|
label: html5Track.label,
|
|
1295
1338
|
kind: html5Track.kind,
|
|
1296
1339
|
width: null,
|
|
@@ -1320,6 +1363,7 @@ shaka.util.StreamUtils = class {
|
|
|
1320
1363
|
originalAudioId: null,
|
|
1321
1364
|
originalTextId: null,
|
|
1322
1365
|
originalImageId: null,
|
|
1366
|
+
originalLanguage: language,
|
|
1323
1367
|
};
|
|
1324
1368
|
|
|
1325
1369
|
return track;
|
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.13",
|
|
5
5
|
"homepage": "https://github.com/shaka-project/shaka-player",
|
|
6
6
|
"author": "Google",
|
|
7
7
|
"maintainers": [
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"karma-coverage": "^2.2.0",
|
|
43
43
|
"karma-jasmine": "^4.0.1",
|
|
44
44
|
"karma-jasmine-ajax": "^0.1.13",
|
|
45
|
-
"karma-local-wd-launcher": "^1.6.
|
|
45
|
+
"karma-local-wd-launcher": "^1.6.4",
|
|
46
46
|
"karma-opera-launcher": "^1.0.0",
|
|
47
47
|
"karma-sourcemap-loader": "^0.3.8",
|
|
48
48
|
"karma-spec-reporter": "^0.0.34",
|
|
@@ -67,7 +67,6 @@
|
|
|
67
67
|
"demoDeps": [
|
|
68
68
|
"awesomplete/awesomplete.css",
|
|
69
69
|
"awesomplete/awesomplete.min.js",
|
|
70
|
-
"codem-isoboxer/dist/iso_boxer.min.js",
|
|
71
70
|
"dialog-polyfill/dialog-polyfill.css",
|
|
72
71
|
"dialog-polyfill/dist/dialog-polyfill.js",
|
|
73
72
|
"eme-encryption-scheme-polyfill/index.js",
|
|
@@ -171,7 +171,10 @@ describe('CastUtils', () => {
|
|
|
171
171
|
}
|
|
172
172
|
});
|
|
173
173
|
|
|
174
|
-
|
|
174
|
+
// Disable because these tests are flakey on ChromeLinux, and this whole
|
|
175
|
+
// module will be removed in
|
|
176
|
+
// https://github.com/shaka-project/shaka-player/issues/4214
|
|
177
|
+
xdescribe('TimeRanges', () => {
|
|
175
178
|
/** @type {!HTMLVideoElement} */
|
|
176
179
|
let video;
|
|
177
180
|
/** @type {!shaka.util.EventManager} */
|