shaka-player 4.6.13 → 4.6.14
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 +16 -0
- package/CONTRIBUTORS +1 -0
- package/dist/locales.js +30 -30
- package/dist/shaka-player.compiled.debug.js +72 -72
- package/dist/shaka-player.compiled.debug.map +2 -2
- package/dist/shaka-player.compiled.js +88 -89
- package/dist/shaka-player.compiled.map +3 -3
- package/dist/shaka-player.ui.debug.js +86 -86
- package/dist/shaka-player.ui.debug.map +2 -2
- package/dist/shaka-player.ui.js +93 -94
- package/dist/shaka-player.ui.map +3 -3
- package/lib/dash/segment_template.js +18 -13
- package/lib/hls/hls_parser.js +2 -2
- package/lib/media/segment_reference.js +4 -1
- package/lib/media/streaming_engine.js +2 -2
- package/lib/player.js +1 -1
- package/lib/util/periods.js +23 -1
- package/lib/util/stream_utils.js +1 -1
- package/package.json +2 -2
- package/test/dash/dash_parser_segment_template_unit.js +1 -1
- package/test/media/buffering_observer_unit.js +13 -0
- package/test/test/util/waiter.js +5 -0
- package/test/transmuxer/transmuxer_integration.js +4 -4
- package/test/util/periods_unit.js +64 -0
|
@@ -755,16 +755,10 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
755
755
|
|
|
756
756
|
this.evict(this.periodStart_);
|
|
757
757
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
if (this.periodEnd_ !== Infinity) {
|
|
763
|
-
// Adjust the last timeline entry to match the period end
|
|
764
|
-
const lastTimePeriod = timeline[timeline.length - 1];
|
|
765
|
-
// NOTE: end should be relative to period start
|
|
766
|
-
lastTimePeriod.end = this.periodEnd_ - this.periodStart_;
|
|
767
|
-
}
|
|
758
|
+
// Do NOT adjust last range to match period end! With high precision
|
|
759
|
+
// timestamps several recalculations may give wrong results on less precise
|
|
760
|
+
// platforms. To mitigate that, we're using cached |periodEnd_| value in
|
|
761
|
+
// find/get() methods whenever possible.
|
|
768
762
|
}
|
|
769
763
|
|
|
770
764
|
/**
|
|
@@ -784,7 +778,7 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
784
778
|
const timeline = this.templateInfo_.timeline;
|
|
785
779
|
|
|
786
780
|
// Early exit if the time isn't within this period
|
|
787
|
-
if (time < this.periodStart_ || time
|
|
781
|
+
if (time < this.periodStart_ || time >= this.periodEnd_) {
|
|
788
782
|
return null;
|
|
789
783
|
}
|
|
790
784
|
|
|
@@ -797,10 +791,14 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
797
791
|
// the references by a fraction of a second. To account for this, we use
|
|
798
792
|
// the start of the next segment as /end/, unless this is the last
|
|
799
793
|
// reference, in which case we use the period end as the /end/
|
|
800
|
-
let end
|
|
794
|
+
let end;
|
|
801
795
|
|
|
802
796
|
if (i < lastIndex) {
|
|
803
797
|
end = timeline[i + 1].start + this.periodStart_;
|
|
798
|
+
} else if (this.periodEnd_ === Infinity) {
|
|
799
|
+
end = range.end + this.periodStart_;
|
|
800
|
+
} else {
|
|
801
|
+
end = this.periodEnd_;
|
|
804
802
|
}
|
|
805
803
|
|
|
806
804
|
if ((time >= start) && (time < end)) {
|
|
@@ -831,6 +829,12 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
831
829
|
.unscaledPresentationTimeOffset + range.unscaledStart;
|
|
832
830
|
const timestampOffset = this.periodStart_ -
|
|
833
831
|
this.templateInfo_.scaledPresentationTimeOffset;
|
|
832
|
+
const trueSegmentEnd = this.periodStart_ + range.end;
|
|
833
|
+
let segmentEnd = trueSegmentEnd;
|
|
834
|
+
if (correctedPosition === this.getNumReferences() - 1 &&
|
|
835
|
+
this.periodEnd_ !== Infinity) {
|
|
836
|
+
segmentEnd = this.periodEnd_;
|
|
837
|
+
}
|
|
834
838
|
|
|
835
839
|
const partialSegmentRefs = [];
|
|
836
840
|
|
|
@@ -901,7 +905,7 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
901
905
|
|
|
902
906
|
ref = new shaka.media.SegmentReference(
|
|
903
907
|
this.periodStart_ + range.start,
|
|
904
|
-
|
|
908
|
+
segmentEnd,
|
|
905
909
|
createUrisCb,
|
|
906
910
|
/* startByte= */ 0,
|
|
907
911
|
/* endByte= */ null,
|
|
@@ -916,6 +920,7 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
916
920
|
shaka.media.SegmentReference.Status.AVAILABLE,
|
|
917
921
|
this.aes128Key_,
|
|
918
922
|
/* allPartialSegments= */ range.partialSegments > 0);
|
|
923
|
+
ref.trueEndTime = trueSegmentEnd;
|
|
919
924
|
this.references[correctedPosition] = ref;
|
|
920
925
|
}
|
|
921
926
|
|
package/lib/hls/hls_parser.js
CHANGED
|
@@ -2831,12 +2831,12 @@ shaka.hls.HlsParser = class {
|
|
|
2831
2831
|
// Don't download the key object until the segment is parsed, to avoid a
|
|
2832
2832
|
// startup delay for long manifests with lots of keys.
|
|
2833
2833
|
keyInfo.fetchKey = async () => {
|
|
2834
|
-
const
|
|
2834
|
+
const keyUris = shaka.hls.Utils.constructSegmentUris(
|
|
2835
2835
|
getUris(), drmTag.getRequiredAttrValue('URI'), variables);
|
|
2836
2836
|
|
|
2837
2837
|
const requestType = shaka.net.NetworkingEngine.RequestType.KEY;
|
|
2838
2838
|
const request = shaka.net.NetworkingEngine.makeRequest(
|
|
2839
|
-
|
|
2839
|
+
keyUris, this.config_.retryParameters);
|
|
2840
2840
|
const keyResponse = await this.makeNetworkRequest_(request, requestType);
|
|
2841
2841
|
|
|
2842
2842
|
// keyResponse.status is undefined when URI is "data:text/plain;base64,"
|
|
@@ -123,7 +123,10 @@ shaka.media.InitSegmentReference = class {
|
|
|
123
123
|
static equal(reference1, reference2) {
|
|
124
124
|
const ArrayUtils = shaka.util.ArrayUtils;
|
|
125
125
|
const BufferUtils = shaka.util.BufferUtils;
|
|
126
|
-
|
|
126
|
+
|
|
127
|
+
if (reference1 === reference2) {
|
|
128
|
+
return true;
|
|
129
|
+
} else if (!reference1 || !reference2) {
|
|
127
130
|
return reference1 == reference2;
|
|
128
131
|
} else {
|
|
129
132
|
return reference1.getStartByte() == reference2.getStartByte() &&
|
|
@@ -2153,8 +2153,8 @@ shaka.media.StreamingEngine = class {
|
|
|
2153
2153
|
const bufferedBehind = presentationTime - startTime;
|
|
2154
2154
|
|
|
2155
2155
|
const overflow = bufferedBehind - bufferBehind;
|
|
2156
|
-
// See: https://github.com/shaka-project/shaka-player/issues/
|
|
2157
|
-
if (overflow <=
|
|
2156
|
+
// See: https://github.com/shaka-project/shaka-player/issues/6240
|
|
2157
|
+
if (overflow <= 1) {
|
|
2158
2158
|
shaka.log.v2(logPrefix,
|
|
2159
2159
|
'buffer behind okay:',
|
|
2160
2160
|
'presentationTime=' + presentationTime,
|
package/lib/player.js
CHANGED
|
@@ -6837,7 +6837,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
|
|
|
6837
6837
|
* @export
|
|
6838
6838
|
*/
|
|
6839
6839
|
// eslint-disable-next-line no-useless-concat
|
|
6840
|
-
shaka.Player.version = 'v4.6.
|
|
6840
|
+
shaka.Player.version = 'v4.6.14' + '-uncompiled'; // x-release-please-version
|
|
6841
6841
|
|
|
6842
6842
|
// Initialize the deprecation system using the version string we just set
|
|
6843
6843
|
// on the player.
|
package/lib/util/periods.js
CHANGED
|
@@ -1180,7 +1180,18 @@ shaka.util.PeriodCombiner = class {
|
|
|
1180
1180
|
return false;
|
|
1181
1181
|
}
|
|
1182
1182
|
|
|
1183
|
-
// If language-based differences haven't decided this, look at
|
|
1183
|
+
// If language-based differences haven't decided this, look at labels.
|
|
1184
|
+
// If available options differ, look does any matches with output stream.
|
|
1185
|
+
if (best.label !== candidate.label) {
|
|
1186
|
+
if (outputStream.label === best.label) {
|
|
1187
|
+
return false;
|
|
1188
|
+
}
|
|
1189
|
+
if (outputStream.label === candidate.label) {
|
|
1190
|
+
return true;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
// If label-based differences haven't decided this, look at roles. If
|
|
1184
1195
|
// the candidate has more roles in common with the output, upgrade to the
|
|
1185
1196
|
// candidate.
|
|
1186
1197
|
if (outputStream.roles.length) {
|
|
@@ -1383,6 +1394,17 @@ shaka.util.PeriodCombiner = class {
|
|
|
1383
1394
|
return false;
|
|
1384
1395
|
}
|
|
1385
1396
|
|
|
1397
|
+
// If language-based differences haven't decided this, look at labels.
|
|
1398
|
+
// If available options differ, look does any matches with output stream.
|
|
1399
|
+
if (best.label !== candidate.label) {
|
|
1400
|
+
if (outputStream.label === best.label) {
|
|
1401
|
+
return false;
|
|
1402
|
+
}
|
|
1403
|
+
if (outputStream.label === candidate.label) {
|
|
1404
|
+
return true;
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1386
1408
|
// If the candidate has more roles in common with the output, upgrade to the
|
|
1387
1409
|
// candidate.
|
|
1388
1410
|
if (outputStream.roles.length) {
|
package/lib/util/stream_utils.js
CHANGED
|
@@ -839,7 +839,7 @@ shaka.util.StreamUtils = class {
|
|
|
839
839
|
// currently don't support 'fLaC', while 'flac' is supported by most
|
|
840
840
|
// major browsers.
|
|
841
841
|
// See https://bugs.chromium.org/p/chromium/issues/detail?id=1422728
|
|
842
|
-
if (codecs === 'fLaC') {
|
|
842
|
+
if (codecs === 'fLaC' && !shaka.util.Platform.isSafari()) {
|
|
843
843
|
return 'flac';
|
|
844
844
|
}
|
|
845
845
|
|
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.6.
|
|
4
|
+
"version": "4.6.14",
|
|
5
5
|
"homepage": "https://github.com/shaka-project/shaka-player",
|
|
6
6
|
"author": "Google",
|
|
7
7
|
"maintainers": [
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"karma-coverage": "^2.2.0",
|
|
44
44
|
"karma-jasmine": "^4.0.1",
|
|
45
45
|
"karma-jasmine-ajax": "^0.1.13",
|
|
46
|
-
"karma-local-wd-launcher": "^1.6.
|
|
46
|
+
"karma-local-wd-launcher": "^1.6.7",
|
|
47
47
|
"karma-opera-launcher": "^1.0.0",
|
|
48
48
|
"karma-sourcemap-loader": "^0.3.8",
|
|
49
49
|
"karma-spec-reporter": "^0.0.34",
|
|
@@ -786,7 +786,7 @@ describe('DashParser SegmentTemplate', () => {
|
|
|
786
786
|
const newTemplateInfo = makeTemplateInfo(newRanges);
|
|
787
787
|
|
|
788
788
|
const newEnd = newRanges[newRanges.length - 1].end;
|
|
789
|
-
index.appendTemplateInfo(newTemplateInfo, newEnd);
|
|
789
|
+
index.appendTemplateInfo(newTemplateInfo, /* periodStart= */ 0, newEnd);
|
|
790
790
|
expect(index.find(newStart)).toBe(10);
|
|
791
791
|
expect(index.find(newEnd - 1.0)).toBe(19);
|
|
792
792
|
});
|
|
@@ -11,15 +11,28 @@ describe('BufferingObserver', () => {
|
|
|
11
11
|
const thresholdAfterStarving = 5;
|
|
12
12
|
const thresholdAfterSatisfied = 2;
|
|
13
13
|
|
|
14
|
+
const originalDateNow = Date.now;
|
|
15
|
+
|
|
16
|
+
/** @type {!Date} */
|
|
17
|
+
let baseTime;
|
|
18
|
+
|
|
14
19
|
/** @type {!shaka.media.BufferingObserver} */
|
|
15
20
|
let controller;
|
|
16
21
|
|
|
17
22
|
beforeEach(() => {
|
|
23
|
+
// Any test using Date needs to have Date mocked to avoid flake.
|
|
24
|
+
baseTime = new Date(2015, 11, 30);
|
|
25
|
+
Date.now = () => baseTime.getTime();
|
|
26
|
+
|
|
18
27
|
controller = new BufferingObserver(
|
|
19
28
|
thresholdAfterStarving,
|
|
20
29
|
thresholdAfterSatisfied);
|
|
21
30
|
});
|
|
22
31
|
|
|
32
|
+
afterEach(() => {
|
|
33
|
+
Date.now = originalDateNow;
|
|
34
|
+
});
|
|
35
|
+
|
|
23
36
|
describe('when satisfied', () => {
|
|
24
37
|
beforeEach(() => {
|
|
25
38
|
controller.setState(State.SATISFIED);
|
package/test/test/util/waiter.js
CHANGED
|
@@ -184,6 +184,7 @@ shaka.test.Waiter = class {
|
|
|
184
184
|
}
|
|
185
185
|
this.eventManager_.unlisten(mediaElement, 'timeupdate');
|
|
186
186
|
this.eventManager_.unlisten(mediaElement, 'ended');
|
|
187
|
+
this.eventManager_.unlisten(mediaElement, 'durationchange');
|
|
187
188
|
};
|
|
188
189
|
|
|
189
190
|
const p = new Promise((resolve) => {
|
|
@@ -202,6 +203,10 @@ shaka.test.Waiter = class {
|
|
|
202
203
|
timer.tickEvery(/* seconds= */ 1);
|
|
203
204
|
this.eventManager_.listen(mediaElement, 'timeupdate', check);
|
|
204
205
|
this.eventManager_.listen(mediaElement, 'ended', check);
|
|
206
|
+
// Some tests on Safari expose a condition where the ended flag can be
|
|
207
|
+
// found in the desired state in a brief window during a durationchange
|
|
208
|
+
// event.
|
|
209
|
+
this.eventManager_.listen(mediaElement, 'durationchange', check);
|
|
205
210
|
});
|
|
206
211
|
|
|
207
212
|
return this.waitUntilGeneric_(goalName, p, cleanup, mediaElement);
|
|
@@ -306,10 +306,10 @@ filterDescribe('Transmuxer Player', checkNoBrokenEdge, () => {
|
|
|
306
306
|
|
|
307
307
|
it('H.265 in TS', async () => {
|
|
308
308
|
const chromeVersion = shaka.util.Platform.chromeVersion();
|
|
309
|
-
if (shaka.util.Platform.isWindows() &&
|
|
310
|
-
|
|
311
|
-
//
|
|
312
|
-
//
|
|
309
|
+
if (shaka.util.Platform.isWindows() && chromeVersion) {
|
|
310
|
+
// It appears that Chrome 122 in Windows is still incorrectly reporting
|
|
311
|
+
// H.265 in MediaSource. Revisit this with a maximum chromeVersion if
|
|
312
|
+
// Chrome ever fixes it.
|
|
313
313
|
pending('Codec H.265 is not supported by the platform.');
|
|
314
314
|
}
|
|
315
315
|
const mimeType = 'video/mp4; codecs="hvc1.2.4.L123.B0"';
|
|
@@ -1060,6 +1060,70 @@ describe('PeriodCombiner', () => {
|
|
|
1060
1060
|
expect(audio2.originalId).toBe('2,4');
|
|
1061
1061
|
});
|
|
1062
1062
|
|
|
1063
|
+
it('Matches streams with labels', async () => {
|
|
1064
|
+
const stream1 = makeAudioStream('en', /* channels= */ 2);
|
|
1065
|
+
stream1.originalId = '1';
|
|
1066
|
+
stream1.bandwidth = 129597;
|
|
1067
|
+
stream1.codecs = 'mp4a.40.2';
|
|
1068
|
+
|
|
1069
|
+
const stream2 = makeAudioStream('en', /* channels= */ 2);
|
|
1070
|
+
stream2.originalId = '2';
|
|
1071
|
+
stream2.bandwidth = 129637;
|
|
1072
|
+
stream2.codecs = 'mp4a.40.2';
|
|
1073
|
+
stream2.label = 'description';
|
|
1074
|
+
|
|
1075
|
+
const stream3 = makeAudioStream('en', /* channels= */ 2);
|
|
1076
|
+
stream3.originalId = '3';
|
|
1077
|
+
stream3.bandwidth = 131037;
|
|
1078
|
+
stream3.codecs = 'mp4a.40.2';
|
|
1079
|
+
|
|
1080
|
+
const stream4 = makeAudioStream('en', /* channels= */ 2);
|
|
1081
|
+
stream4.originalId = '4';
|
|
1082
|
+
stream4.bandwidth = 131034;
|
|
1083
|
+
stream4.codecs = 'mp4a.40.2';
|
|
1084
|
+
stream4.label = 'description';
|
|
1085
|
+
|
|
1086
|
+
/** @type {!Array.<shaka.extern.Period>} */
|
|
1087
|
+
const periods = [
|
|
1088
|
+
{
|
|
1089
|
+
id: '0',
|
|
1090
|
+
videoStreams: [
|
|
1091
|
+
makeVideoStream(1080),
|
|
1092
|
+
],
|
|
1093
|
+
audioStreams: [
|
|
1094
|
+
stream1,
|
|
1095
|
+
stream2,
|
|
1096
|
+
],
|
|
1097
|
+
textStreams: [],
|
|
1098
|
+
imageStreams: [],
|
|
1099
|
+
},
|
|
1100
|
+
{
|
|
1101
|
+
id: '1',
|
|
1102
|
+
videoStreams: [
|
|
1103
|
+
makeVideoStream(1080),
|
|
1104
|
+
],
|
|
1105
|
+
audioStreams: [
|
|
1106
|
+
stream3,
|
|
1107
|
+
stream4,
|
|
1108
|
+
],
|
|
1109
|
+
textStreams: [],
|
|
1110
|
+
imageStreams: [],
|
|
1111
|
+
},
|
|
1112
|
+
];
|
|
1113
|
+
|
|
1114
|
+
await combiner.combinePeriods(periods, /* isDynamic= */ true);
|
|
1115
|
+
const variants = combiner.getVariants();
|
|
1116
|
+
expect(variants.length).toBe(2);
|
|
1117
|
+
// We can use the originalId field to see what each track is composed of.
|
|
1118
|
+
const audio1 = variants[0].audio;
|
|
1119
|
+
expect(audio1.label).toBe(null);
|
|
1120
|
+
expect(audio1.originalId).toBe('1,3');
|
|
1121
|
+
|
|
1122
|
+
const audio2 = variants[1].audio;
|
|
1123
|
+
expect(audio2.label).toBe('description');
|
|
1124
|
+
expect(audio2.originalId).toBe('2,4');
|
|
1125
|
+
});
|
|
1126
|
+
|
|
1063
1127
|
it('Matches streams with related codecs', async () => {
|
|
1064
1128
|
const stream1 = makeVideoStream(1080);
|
|
1065
1129
|
stream1.originalId = '1';
|