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.
@@ -755,16 +755,10 @@ shaka.dash.TimelineSegmentIndex = class extends shaka.media.SegmentIndex {
755
755
 
756
756
  this.evict(this.periodStart_);
757
757
 
758
- if (timeline.length === 0) {
759
- return;
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 > this.periodEnd_) {
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 = range.end + this.periodStart_;
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
- this.periodStart_ + range.end,
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
 
@@ -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 keyUri = shaka.hls.Utils.constructSegmentUris(
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
- [keyUri], this.config_.retryParameters);
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
- if (!reference1 || !reference2) {
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/2982
2157
- if (overflow <= 0.01) {
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.13' + '-uncompiled'; // x-release-please-version
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.
@@ -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 roles. If
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) {
@@ -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.13",
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.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);
@@ -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
- chromeVersion && chromeVersion === 117) {
311
- // It appears that Chrome 117 beta in Windows is incorrectly reporting
312
- // H.265 in MediaCapabilities
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';