shaka-player 4.7.6 → 4.7.8

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.
Files changed (40) hide show
  1. package/AUTHORS +2 -0
  2. package/CONTRIBUTORS +2 -0
  3. package/dist/locales.js +30 -30
  4. package/dist/shaka-player.compiled.d.ts +1 -1
  5. package/dist/shaka-player.compiled.debug.d.ts +1 -1
  6. package/dist/shaka-player.compiled.debug.externs.js +2 -1
  7. package/dist/shaka-player.compiled.debug.js +94 -93
  8. package/dist/shaka-player.compiled.debug.map +3 -3
  9. package/dist/shaka-player.compiled.externs.js +2 -1
  10. package/dist/shaka-player.compiled.js +1105 -1099
  11. package/dist/shaka-player.compiled.map +3 -3
  12. package/dist/shaka-player.ui.d.ts +13 -2
  13. package/dist/shaka-player.ui.debug.d.ts +13 -2
  14. package/dist/shaka-player.ui.debug.externs.js +3 -1
  15. package/dist/shaka-player.ui.debug.js +257 -256
  16. package/dist/shaka-player.ui.debug.map +3 -3
  17. package/dist/shaka-player.ui.externs.js +3 -1
  18. package/dist/shaka-player.ui.js +1229 -1223
  19. package/dist/shaka-player.ui.map +3 -3
  20. package/lib/hls/hls_parser.js +14 -6
  21. package/lib/media/drm_engine.js +9 -0
  22. package/lib/mss/mss_parser.js +2 -0
  23. package/lib/offline/storage.js +4 -0
  24. package/lib/player.js +14 -3
  25. package/lib/polyfill/media_capabilities.js +23 -3
  26. package/lib/transmuxer/aac_transmuxer.js +2 -0
  27. package/lib/transmuxer/ac3_transmuxer.js +2 -0
  28. package/lib/transmuxer/ec3_transmuxer.js +2 -0
  29. package/lib/transmuxer/h264.js +28 -1
  30. package/lib/transmuxer/h265.js +25 -5
  31. package/lib/transmuxer/mp3_transmuxer.js +2 -0
  32. package/lib/transmuxer/ts_transmuxer.js +12 -0
  33. package/lib/util/cmcd_manager.js +13 -0
  34. package/lib/util/manifest_parser_utils.js +2 -0
  35. package/lib/util/mp4_generator.js +31 -2
  36. package/lib/util/stream_utils.js +2 -10
  37. package/lib/util/ts_parser.js +7 -4
  38. package/package.json +1 -1
  39. package/ui/externs/ui.js +24 -0
  40. package/ui/play_button.js +3 -0
@@ -447,8 +447,9 @@ shaka.hls.HlsParser = class {
447
447
  const {segments, bandwidth} = this.createSegments_(
448
448
  playlist, stream, mediaSequenceToStartTime, mediaVariables,
449
449
  streamInfo.getUris);
450
-
451
- stream.bandwidth = bandwidth;
450
+ if (bandwidth) {
451
+ stream.bandwidth = bandwidth;
452
+ }
452
453
 
453
454
  stream.segmentIndex.mergeAndEvict(
454
455
  segments, this.presentationTimeline_.getSegmentAvailabilityStart());
@@ -1383,7 +1384,7 @@ shaka.hls.HlsParser = class {
1383
1384
  videoLayout = videoLayout || 'CH-MONO';
1384
1385
 
1385
1386
  const streamInfos = this.createStreamInfosForVariantTags_(tags,
1386
- mediaTags, resolution, frameRate);
1387
+ mediaTags, resolution, frameRate, bandwidth);
1387
1388
 
1388
1389
  goog.asserts.assert(streamInfos.audio.length ||
1389
1390
  streamInfos.video.length, 'We should have created a stream!');
@@ -1411,10 +1412,12 @@ shaka.hls.HlsParser = class {
1411
1412
  * @param {!Array.<!shaka.hls.Tag>} mediaTags
1412
1413
  * @param {?string} resolution
1413
1414
  * @param {?string} frameRate
1415
+ * @param {number} bandwidth
1414
1416
  * @return {!shaka.hls.HlsParser.StreamInfos}
1415
1417
  * @private
1416
1418
  */
1417
- createStreamInfosForVariantTags_(tags, mediaTags, resolution, frameRate) {
1419
+ createStreamInfosForVariantTags_(
1420
+ tags, mediaTags, resolution, frameRate, bandwidth) {
1418
1421
  const ContentType = shaka.util.ManifestParserUtils.ContentType;
1419
1422
 
1420
1423
  /** @type {shaka.hls.HlsParser.StreamInfos} */
@@ -1549,6 +1552,9 @@ shaka.hls.HlsParser = class {
1549
1552
  if (globalGroupId) {
1550
1553
  streamInfo.stream.groupId = globalGroupId;
1551
1554
  }
1555
+ if (!streamInfos.length) {
1556
+ streamInfo.stream.bandwidth = bandwidth;
1557
+ }
1552
1558
  res[streamInfo.stream.type] = [streamInfo];
1553
1559
  }
1554
1560
  return res;
@@ -2252,7 +2258,7 @@ shaka.hls.HlsParser = class {
2252
2258
  stream.drmInfos = realStream.drmInfos;
2253
2259
  stream.keyIds = realStream.keyIds;
2254
2260
  stream.mimeType = realStream.mimeType;
2255
- stream.bandwidth = realStream.bandwidth;
2261
+ stream.bandwidth = stream.bandwidth || realStream.bandwidth;
2256
2262
  stream.codecs = stream.codecs || realStream.codecs;
2257
2263
 
2258
2264
  // Since we lazy-loaded this content, the player may need to create new
@@ -2531,7 +2537,9 @@ shaka.hls.HlsParser = class {
2531
2537
 
2532
2538
  const {segments, bandwidth} = this.createSegments_(
2533
2539
  playlist, stream, mediaSequenceToStartTime, mediaVariables, getUris);
2534
- stream.bandwidth = bandwidth;
2540
+ if (bandwidth) {
2541
+ stream.bandwidth = bandwidth;
2542
+ }
2535
2543
 
2536
2544
  // This new calculation is necessary for Low Latency streams.
2537
2545
  if (this.isLive_()) {
@@ -542,6 +542,15 @@ shaka.media.DrmEngine = class {
542
542
  }
543
543
  }
544
544
 
545
+ /**
546
+ * Returns true if the manifest has init data.
547
+ *
548
+ * @return {boolean}
549
+ */
550
+ hasManifestInitData() {
551
+ return !!this.manifestInitData_;
552
+ }
553
+
545
554
  /**
546
555
  * Sets the server certificate based on the current DrmInfo.
547
556
  *
@@ -661,6 +661,8 @@ shaka.mss.MssParser = class {
661
661
  videoNalus: videoNalus,
662
662
  audioConfig: new Uint8Array([]),
663
663
  videoConfig: new Uint8Array([]),
664
+ hSpacing: 0,
665
+ vSpacing: 0,
664
666
  data: null, // Data is not necessary for init segement.
665
667
  stream: stream,
666
668
  };
@@ -400,6 +400,10 @@ shaka.offline.Storage = class {
400
400
  downloader, config, activeHandle.cell, manifest, drmEngine);
401
401
  this.ensureNotDestroyed_();
402
402
 
403
+ this.setManifestDrmFields_(manifest, manifestDB, drmEngine, config);
404
+ await activeHandle.cell.updateManifest(manifestId, manifestDB);
405
+ this.ensureNotDestroyed_();
406
+
403
407
  const offlineUri = shaka.offline.OfflineUri.manifest(
404
408
  activeHandle.path.mechanism, activeHandle.path.cell, manifestId);
405
409
 
package/lib/player.js CHANGED
@@ -723,6 +723,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
723
723
 
724
724
  if (shaka.Player.adManagerFactory_) {
725
725
  this.adManager_ = shaka.Player.adManagerFactory_();
726
+ this.adManager_.configure(this.config_.ads);
726
727
  }
727
728
 
728
729
  // If the browser comes back online after being offline, then try to play
@@ -4691,6 +4692,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
4691
4692
  shaka.util.Error.Code.CONTENT_NOT_LOADED);
4692
4693
  }
4693
4694
 
4695
+ if (kind != 'subtitles' && kind != 'captions') {
4696
+ shaka.log.alwaysWarn(
4697
+ 'Using a kind value different of `subtitles` or `captions` can ' +
4698
+ 'cause unwanted issues.');
4699
+ }
4700
+
4694
4701
  if (!mimeType) {
4695
4702
  mimeType = await this.getTextMimetype_(uri);
4696
4703
  }
@@ -6494,6 +6501,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6494
6501
  const restrictedStatuses = shaka.Player.restrictedStatuses_;
6495
6502
  let tracksChanged = false;
6496
6503
 
6504
+ goog.asserts.assert(this.drmEngine_, 'drmEngine should be non-null here.');
6505
+
6497
6506
  // Only filter tracks for keys if we have some key statuses to look at.
6498
6507
  if (keyIds.length) {
6499
6508
  for (const variant of this.manifest_.variants) {
@@ -6509,8 +6518,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
6509
6518
 
6510
6519
  for (const keyId of stream.keyIds) {
6511
6520
  const keyStatus = keyStatusMap[isGlobalStatus ? '00' : keyId];
6512
- variant.allowedByKeySystem = variant.allowedByKeySystem &&
6513
- !!keyStatus && !restrictedStatuses.includes(keyStatus);
6521
+ if (keyStatus || this.drmEngine_.hasManifestInitData()) {
6522
+ variant.allowedByKeySystem = variant.allowedByKeySystem &&
6523
+ !!keyStatus && !restrictedStatuses.includes(keyStatus);
6524
+ }
6514
6525
  }
6515
6526
  }
6516
6527
 
@@ -6914,7 +6925,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
6914
6925
  * @export
6915
6926
  */
6916
6927
  // eslint-disable-next-line no-useless-concat
6917
- shaka.Player.version = 'v4.7.6' + '-uncompiled'; // x-release-please-version
6928
+ shaka.Player.version = 'v4.7.8' + '-uncompiled'; // x-release-please-version
6918
6929
 
6919
6930
  // Initialize the deprecation system using the version string we just set
6920
6931
  // on the player.
@@ -141,8 +141,15 @@ shaka.polyfill.MediaCapabilities = class {
141
141
  }
142
142
 
143
143
  if (audioConfig) {
144
- const contentType = audioConfig.contentType;
145
- const isSupported = Capabilities.isTypeSupported(contentType);
144
+ let isSupported;
145
+ if (shaka.util.Platform.isChromecast() &&
146
+ audioConfig.spatialRendering) {
147
+ const extendedType =
148
+ audioConfig.contentType + '; spatialRendering=true';
149
+ isSupported = Capabilities.isTypeSupported(extendedType);
150
+ } else {
151
+ isSupported = Capabilities.isTypeSupported(audioConfig.contentType);
152
+ }
146
153
  if (!isSupported) {
147
154
  return res;
148
155
  }
@@ -184,10 +191,23 @@ shaka.polyfill.MediaCapabilities = class {
184
191
  const videoCapabilities = [];
185
192
 
186
193
  if (mediaCapkeySystemConfig.audio) {
187
- const capability = {
194
+ let capability = {
188
195
  robustness: mediaCapkeySystemConfig.audio.robustness || '',
189
196
  contentType: mediaDecodingConfig.audio.contentType,
190
197
  };
198
+
199
+ // Some Tizen devices seem to misreport AC-3 support, but correctly
200
+ // report EC-3 support. So query EC-3 as a fallback for AC-3.
201
+ // See https://github.com/shaka-project/shaka-player/issues/2989 for
202
+ // details.
203
+ if (shaka.util.Platform.isTizen() &&
204
+ mediaDecodingConfig.audio.contentType.includes('codecs="ac-3"')) {
205
+ capability = {
206
+ robustness: capability.robustness,
207
+ contentType: 'audio/mp4; codecs="ec-3"',
208
+ };
209
+ }
210
+
191
211
  audioCapabilities.push(capability);
192
212
  }
193
213
 
@@ -195,6 +195,8 @@ shaka.transmuxer.AacTransmuxer = class {
195
195
  videoNalus: [],
196
196
  audioConfig: new Uint8Array([]),
197
197
  videoConfig: new Uint8Array([]),
198
+ hSpacing: 0,
199
+ vSpacing: 0,
198
200
  data: {
199
201
  sequenceNumber: this.frameIndex_,
200
202
  baseMediaDecodeTime: baseMediaDecodeTime,
@@ -184,6 +184,8 @@ shaka.transmuxer.Ac3Transmuxer = class {
184
184
  videoNalus: [],
185
185
  audioConfig: audioConfig,
186
186
  videoConfig: new Uint8Array([]),
187
+ hSpacing: 0,
188
+ vSpacing: 0,
187
189
  data: {
188
190
  sequenceNumber: this.frameIndex_,
189
191
  baseMediaDecodeTime: baseMediaDecodeTime,
@@ -184,6 +184,8 @@ shaka.transmuxer.Ec3Transmuxer = class {
184
184
  videoNalus: [],
185
185
  audioConfig: audioConfig,
186
186
  videoConfig: new Uint8Array([]),
187
+ hSpacing: 0,
188
+ vSpacing: 0,
187
189
  data: {
188
190
  sequenceNumber: this.frameIndex_,
189
191
  baseMediaDecodeTime: baseMediaDecodeTime,
@@ -20,7 +20,8 @@ shaka.transmuxer.H264 = class {
20
20
  * describes the properties of upcoming video frames.
21
21
  *
22
22
  * @param {!Array.<shaka.extern.VideoNalu>} nalus
23
- * @return {?{height: number, width: number, videoConfig: !Uint8Array}}
23
+ * @return {?{height: number, width: number, videoConfig: !Uint8Array,
24
+ * hSpacing: number, vSpacing: number}}
24
25
  */
25
26
  static parseInfo(nalus) {
26
27
  const H264 = shaka.transmuxer.H264;
@@ -129,6 +130,30 @@ shaka.transmuxer.H264 = class {
129
130
  frameCropBottomOffset = expGolombDecoder.readUnsignedExpGolomb();
130
131
  }
131
132
 
133
+ let hSpacing = 1;
134
+ let vSpacing = 1;
135
+
136
+ // vui_parameters_present_flag
137
+ if (expGolombDecoder.readBoolean()) {
138
+ // aspect_ratio_info_present_flag
139
+ if (expGolombDecoder.readBoolean()) {
140
+ const aspectRatioIdc = expGolombDecoder.readUnsignedByte();
141
+ const hSpacingTable = [
142
+ 1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2,
143
+ ];
144
+ const vSpacingTable = [
145
+ 1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1,
146
+ ];
147
+ if (aspectRatioIdc > 0 && aspectRatioIdc < 16) {
148
+ hSpacing = hSpacingTable[aspectRatioIdc - 1];
149
+ vSpacing = vSpacingTable[aspectRatioIdc - 1];
150
+ } else if (aspectRatioIdc === 255) {
151
+ hSpacing = expGolombDecoder.readBits(16);
152
+ vSpacing = expGolombDecoder.readBits(16);
153
+ }
154
+ }
155
+ }
156
+
132
157
  const height = ((2 - frameMbsOnlyFlag) *
133
158
  (picHeightInMapUnitsMinus1 + 1) * 16) - (frameCropTopOffset * 2) -
134
159
  (frameCropBottomOffset * 2);
@@ -165,6 +190,8 @@ shaka.transmuxer.H264 = class {
165
190
  height,
166
191
  width,
167
192
  videoConfig,
193
+ hSpacing,
194
+ vSpacing,
168
195
  };
169
196
  }
170
197
 
@@ -20,7 +20,8 @@ shaka.transmuxer.H265 = class {
20
20
  * describes the properties of upcoming video frames.
21
21
  *
22
22
  * @param {!Array.<shaka.extern.VideoNalu>} nalus
23
- * @return {?{height: number, width: number, videoConfig: !Uint8Array}}
23
+ * @return {?{height: number, width: number, videoConfig: !Uint8Array,
24
+ * hSpacing: number, vSpacing: number}}
24
25
  */
25
26
  static parseInfo(nalus) {
26
27
  const H265 = shaka.transmuxer.H265;
@@ -87,6 +88,8 @@ shaka.transmuxer.H265 = class {
87
88
  height: spsConfiguration.height,
88
89
  width: spsConfiguration.width,
89
90
  videoConfig,
91
+ hSpacing: spsConfiguration.sarWidth,
92
+ vSpacing: spsConfiguration.sarHeight,
90
93
  };
91
94
  }
92
95
 
@@ -298,6 +301,8 @@ shaka.transmuxer.H265 = class {
298
301
  }
299
302
  }
300
303
  let defaultDisplayWindowFlag = false; // for calc offset
304
+ let sarWidth = 1;
305
+ let sarHeight = 1;
301
306
  let minSpatialSegmentationIdc = 0; // for hvcC
302
307
  gb.readBoolean(); // sps_temporal_mvp_enabled_flag
303
308
  gb.readBoolean(); // strong_intra_smoothing_enabled_flag
@@ -306,9 +311,18 @@ shaka.transmuxer.H265 = class {
306
311
  const aspectRatioInfoPresentFlag = gb.readBoolean();
307
312
  if (aspectRatioInfoPresentFlag) {
308
313
  const aspectRatioIdc = gb.readUnsignedByte();
309
- if (aspectRatioIdc === 255) {
310
- gb.readBits(16); // sar_width
311
- gb.readBits(16); // sar_height
314
+ const sarWidthTable = [
315
+ 1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2,
316
+ ];
317
+ const sarHeightTable = [
318
+ 1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1,
319
+ ];
320
+ if (aspectRatioIdc > 0 && aspectRatioIdc < 16) {
321
+ sarWidth = sarWidthTable[aspectRatioIdc - 1];
322
+ sarHeight = sarHeightTable[aspectRatioIdc - 1];
323
+ } else if (aspectRatioIdc === 255) {
324
+ sarWidth = gb.readBits(16);
325
+ sarHeight = gb.readBits(16);
312
326
  }
313
327
  }
314
328
  const overscanInfoPresentFlag = gb.readBoolean();
@@ -459,6 +473,8 @@ shaka.transmuxer.H265 = class {
459
473
  bitDepthChromaMinus8,
460
474
  width: codecWidth,
461
475
  height: codecHeight,
476
+ sarWidth: sarWidth,
477
+ sarHeight: sarHeight,
462
478
  };
463
479
  }
464
480
 
@@ -773,7 +789,9 @@ shaka.transmuxer.H265.VPSConfiguration;
773
789
  * bitDepthLumaMinus8: number,
774
790
  * bitDepthChromaMinus8: number,
775
791
  * width: number,
776
- * height: number
792
+ * height: number,
793
+ * sarWidth: number,
794
+ * sarHeight: number
777
795
  * }}
778
796
  *
779
797
  * @property {number} generalProfileSpace
@@ -797,6 +815,8 @@ shaka.transmuxer.H265.VPSConfiguration;
797
815
  * @property {number} bitDepthChromaMinus8
798
816
  * @property {number} width
799
817
  * @property {number} height
818
+ * @property {number} sarWidth
819
+ * @property {number} sarHeight
800
820
  */
801
821
  shaka.transmuxer.H265.SPSConfiguration;
802
822
 
@@ -176,6 +176,8 @@ shaka.transmuxer.Mp3Transmuxer = class {
176
176
  videoNalus: [],
177
177
  audioConfig: new Uint8Array([]),
178
178
  videoConfig: new Uint8Array([]),
179
+ hSpacing: 0,
180
+ vSpacing: 0,
179
181
  data: {
180
182
  sequenceNumber: this.frameIndex_,
181
183
  baseMediaDecodeTime: baseMediaDecodeTime,
@@ -409,6 +409,8 @@ shaka.transmuxer.TsTransmuxer = class {
409
409
  videoNalus: [],
410
410
  audioConfig: new Uint8Array([]),
411
411
  videoConfig: new Uint8Array([]),
412
+ hSpacing: 0,
413
+ vSpacing: 0,
412
414
  data: {
413
415
  sequenceNumber: this.frameIndex_,
414
416
  baseMediaDecodeTime: baseMediaDecodeTime,
@@ -500,6 +502,8 @@ shaka.transmuxer.TsTransmuxer = class {
500
502
  videoNalus: [],
501
503
  audioConfig: audioConfig,
502
504
  videoConfig: new Uint8Array([]),
505
+ hSpacing: 0,
506
+ vSpacing: 0,
503
507
  data: {
504
508
  sequenceNumber: this.frameIndex_,
505
509
  baseMediaDecodeTime: baseMediaDecodeTime,
@@ -591,6 +595,8 @@ shaka.transmuxer.TsTransmuxer = class {
591
595
  videoNalus: [],
592
596
  audioConfig: audioConfig,
593
597
  videoConfig: new Uint8Array([]),
598
+ hSpacing: 0,
599
+ vSpacing: 0,
594
600
  data: {
595
601
  sequenceNumber: this.frameIndex_,
596
602
  baseMediaDecodeTime: baseMediaDecodeTime,
@@ -677,6 +683,8 @@ shaka.transmuxer.TsTransmuxer = class {
677
683
  videoNalus: [],
678
684
  audioConfig: new Uint8Array([]),
679
685
  videoConfig: new Uint8Array([]),
686
+ hSpacing: 0,
687
+ vSpacing: 0,
680
688
  data: {
681
689
  sequenceNumber: this.frameIndex_,
682
690
  baseMediaDecodeTime: baseMediaDecodeTime,
@@ -769,6 +777,8 @@ shaka.transmuxer.TsTransmuxer = class {
769
777
  videoNalus: [],
770
778
  audioConfig: new Uint8Array([]),
771
779
  videoConfig: info.videoConfig,
780
+ hSpacing: info.hSpacing,
781
+ vSpacing: info.vSpacing,
772
782
  data: {
773
783
  sequenceNumber: this.frameIndex_,
774
784
  baseMediaDecodeTime: baseMediaDecodeTime,
@@ -861,6 +871,8 @@ shaka.transmuxer.TsTransmuxer = class {
861
871
  videoNalus: [],
862
872
  audioConfig: new Uint8Array([]),
863
873
  videoConfig: info.videoConfig,
874
+ hSpacing: info.hSpacing,
875
+ vSpacing: info.vSpacing,
864
876
  data: {
865
877
  sequenceNumber: this.frameIndex_,
866
878
  baseMediaDecodeTime: baseMediaDecodeTime,
@@ -65,6 +65,9 @@ shaka.util.CmcdManager = class {
65
65
  */
66
66
  configure(config) {
67
67
  this.config_ = config;
68
+ if (this.config_.sessionId && this.config_.sessionId != this.sid_) {
69
+ this.sid_ = '';
70
+ }
68
71
  }
69
72
 
70
73
  /**
@@ -407,6 +410,15 @@ shaka.util.CmcdManager = class {
407
410
  */
408
411
  getObjectTypeFromMimeType_(mimeType) {
409
412
  switch (mimeType.toLowerCase()) {
413
+ case 'audio/mp4':
414
+ case 'audio/webm':
415
+ case 'audio/ogg':
416
+ case 'audio/mpeg':
417
+ case 'audio/aac':
418
+ case 'audio/flac':
419
+ case 'audio/wav':
420
+ return shaka.util.CmcdManager.ObjectType.AUDIO;
421
+
410
422
  case 'video/webm':
411
423
  case 'video/mp4':
412
424
  case 'video/mpeg':
@@ -417,6 +429,7 @@ shaka.util.CmcdManager = class {
417
429
  case 'application/vnd.apple.mpegurl':
418
430
  case 'application/dash+xml':
419
431
  case 'video/vnd.mpeg.dash.mpd':
432
+ case 'application/vnd.ms-sstr+xml':
420
433
  return shaka.util.CmcdManager.ObjectType.MANIFEST;
421
434
 
422
435
  default:
@@ -179,6 +179,8 @@ shaka.util.ManifestParserUtils.VIDEO_CODEC_REGEXPS_ = [
179
179
  /^avc/,
180
180
  /^hev/,
181
181
  /^hvc/,
182
+ /^vvc/,
183
+ /^vvi/,
182
184
  /^vp0?[89]/,
183
185
  /^av01/,
184
186
  /^dvh/,
@@ -371,12 +371,13 @@ shaka.util.Mp4Generator = class {
371
371
  ]);
372
372
 
373
373
  let boxName = 'avc1';
374
+ const paspBox = this.pasp_(streamInfo);
374
375
  let sinfBox = new Uint8Array([]);
375
376
  if (streamInfo.encrypted) {
376
377
  sinfBox = this.sinf_(streamInfo);
377
378
  boxName = 'encv';
378
379
  }
379
- return Mp4Generator.box(boxName, avc1Bytes, avcCBox, sinfBox);
380
+ return Mp4Generator.box(boxName, avc1Bytes, avcCBox, paspBox, sinfBox);
380
381
  }
381
382
 
382
383
  /**
@@ -500,12 +501,34 @@ shaka.util.Mp4Generator = class {
500
501
  ]);
501
502
 
502
503
  let boxName = 'hvc1';
504
+ const paspBox = this.pasp_(streamInfo);
503
505
  let sinfBox = new Uint8Array([]);
504
506
  if (streamInfo.encrypted) {
505
507
  sinfBox = this.sinf_(streamInfo);
506
508
  boxName = 'encv';
507
509
  }
508
- return Mp4Generator.box(boxName, hvc1Bytes, hvcCBox, sinfBox);
510
+ return Mp4Generator.box(boxName, hvc1Bytes, hvcCBox, paspBox, sinfBox);
511
+ }
512
+
513
+ /**
514
+ * Generate a PASP box
515
+ *
516
+ * @param {shaka.util.Mp4Generator.StreamInfo} streamInfo
517
+ * @return {!Uint8Array}
518
+ * @private
519
+ */
520
+ pasp_(streamInfo) {
521
+ if (!streamInfo.hSpacing && !streamInfo.vSpacing) {
522
+ return new Uint8Array([]);
523
+ }
524
+ const Mp4Generator = shaka.util.Mp4Generator;
525
+ const hSpacing = streamInfo.hSpacing;
526
+ const vSpacing = streamInfo.vSpacing;
527
+ const bytes = new Uint8Array([
528
+ ...this.breakNumberIntoBytes_(hSpacing, 4), // hSpacing
529
+ ...this.breakNumberIntoBytes_(vSpacing, 4), // vSpacing
530
+ ]);
531
+ return Mp4Generator.box('pasp', bytes);
509
532
  }
510
533
 
511
534
  /**
@@ -1301,6 +1324,8 @@ shaka.util.Mp4Generator.DINF_ = new Uint8Array([]);
1301
1324
  * videoNalus: !Array.<string>,
1302
1325
  * audioConfig: !Uint8Array,
1303
1326
  * videoConfig: !Uint8Array,
1327
+ * hSpacing: number,
1328
+ * vSpacing: number,
1304
1329
  * data: ?shaka.util.Mp4Generator.Data,
1305
1330
  * stream: !shaka.extern.Stream
1306
1331
  * }}
@@ -1325,6 +1350,10 @@ shaka.util.Mp4Generator.DINF_ = new Uint8Array([]);
1325
1350
  * The stream's audio config.
1326
1351
  * @property {!Uint8Array} videoConfig
1327
1352
  * The stream's video config.
1353
+ * @property {number} hSpacing
1354
+ * The stream's video horizontal spacing of pixels.
1355
+ * @property {number} vSpacing
1356
+ * The stream's video vertial spacing of pixels.
1328
1357
  * @property {?shaka.util.Mp4Generator.Data} data
1329
1358
  * The stream's data.
1330
1359
  * @property {!shaka.extern.Stream} stream
@@ -162,7 +162,7 @@ shaka.util.StreamUtils = class {
162
162
  const currentCodec =
163
163
  MimeUtils.getNormalizedCodec(stream.codecs);
164
164
  if (previousCodec == currentCodec) {
165
- if (stream.bandwidth < previousStream.bandwidth) {
165
+ if (stream.bandwidth > previousStream.bandwidth) {
166
166
  validVideoStreams.push(stream);
167
167
  validVideoIds.push(stream.id);
168
168
  }
@@ -917,15 +917,7 @@ shaka.util.StreamUtils = class {
917
917
  return 'opus';
918
918
  }
919
919
 
920
- // Some Tizen devices seem to misreport AC-3 support, but correctly
921
- // report EC-3 support. So query EC-3 as a fallback for AC-3.
922
- // See https://github.com/shaka-project/shaka-player/issues/2989 for
923
- // details.
924
- if (shaka.util.Platform.isTizen()) {
925
- return codecs.toLowerCase() == 'ac-3' ? 'ec-3' : codecs;
926
- } else {
927
- return codecs;
928
- }
920
+ return codecs;
929
921
  }
930
922
 
931
923
 
@@ -446,10 +446,11 @@ shaka.util.TsParser = class {
446
446
  *
447
447
  * @param {shaka.extern.MPEG_PES} pes
448
448
  * @param {?shaka.extern.VideoNalu=} lastNalu
449
+ * @param {?number=} lastState
449
450
  * @return {!Array.<shaka.extern.VideoNalu>}
450
451
  * @export
451
452
  */
452
- parseNalus(pes, lastNalu) {
453
+ parseNalus(pes, lastNalu, lastState) {
453
454
  const timescale = shaka.util.TsParser.Timescale;
454
455
  const time = pes.pts ? pes.pts / timescale : null;
455
456
  const data = pes.data;
@@ -465,7 +466,7 @@ shaka.util.TsParser = class {
465
466
  // precede each NALU. A start code is 2 or 3 0x00 bytes followed with a
466
467
  // 0x01 byte. e.g. 0x000001 or 0x00000001.
467
468
  // More info in: https://stackoverflow.com/questions/24884827/possible-locations-for-sequence-picture-parameter-sets-for-h-264-stream/24890903#24890903
468
- let numZeros = 0;
469
+ let numZeros = lastState || 0;
469
470
 
470
471
  /** @type {!Array.<shaka.extern.VideoNalu>} */
471
472
  const nalus = [];
@@ -490,7 +491,7 @@ shaka.util.TsParser = class {
490
491
  const startCodeSize = numZeros > 3 ? 3 : numZeros;
491
492
  const lastByteToKeep = i - startCodeSize;
492
493
  // Optimization
493
- if (lastByteToKeep != 0) {
494
+ if (lastState && lastByteToKeep != 0) {
494
495
  const prevData = data.subarray(0, lastByteToKeep);
495
496
  lastNalu.data = shaka.util.Uint8ArrayUtils.concat(
496
497
  lastNalu.data, prevData);
@@ -572,6 +573,7 @@ shaka.util.TsParser = class {
572
573
  lastNalu.fullData = shaka.util.Uint8ArrayUtils.concat(
573
574
  lastNalu.fullData, data);
574
575
  }
576
+ lastState = Math.min(3, numZeros);
575
577
  return nalus;
576
578
  }
577
579
 
@@ -676,8 +678,9 @@ shaka.util.TsParser = class {
676
678
  }
677
679
  if (naluProcessing) {
678
680
  let lastNalu;
681
+ let lastState;
679
682
  for (const pes of this.videoPes_) {
680
- pes.nalus = this.parseNalus(pes, lastNalu);
683
+ pes.nalus = this.parseNalus(pes, lastNalu, lastState);
681
684
  if (pes.nalus.length) {
682
685
  lastNalu = pes.nalus[pes.nalus.length - 1];
683
686
  }
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.7.6",
4
+ "version": "4.7.8",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
package/ui/externs/ui.js CHANGED
@@ -486,3 +486,27 @@ shaka.extern.IUISeekBar.Factory = class {
486
486
  */
487
487
  create(rootElement, controls) {}
488
488
  };
489
+
490
+ /**
491
+ * @interface
492
+ * @exportDoc
493
+ */
494
+ shaka.extern.IUIPlayButton = class {
495
+ /**
496
+ * @param {!HTMLElement} parent
497
+ * @param {!shaka.ui.Controls} controls
498
+ */
499
+ constructor(parent, controls) {
500
+ /**
501
+ * @protected {!HTMLButtonElement}
502
+ * @exportDoc
503
+ */
504
+ this.button;
505
+ }
506
+
507
+ /** @return {boolean} */
508
+ isPaused() {}
509
+
510
+ /** @return {boolean} */
511
+ isEnded() {}
512
+ };
package/ui/play_button.js CHANGED
@@ -16,6 +16,7 @@ goog.requireType('shaka.ui.Controls');
16
16
 
17
17
  /**
18
18
  * @extends {shaka.ui.Element}
19
+ * @implements {shaka.extern.IUIPlayButton}
19
20
  * @export
20
21
  */
21
22
  shaka.ui.PlayButton = class extends shaka.ui.Element {
@@ -95,6 +96,7 @@ shaka.ui.PlayButton = class extends shaka.ui.Element {
95
96
  /**
96
97
  * @return {boolean}
97
98
  * @protected
99
+ * @override
98
100
  */
99
101
  isPaused() {
100
102
  if (this.ad && this.ad.isLinear()) {
@@ -107,6 +109,7 @@ shaka.ui.PlayButton = class extends shaka.ui.Element {
107
109
  /**
108
110
  * @return {boolean}
109
111
  * @protected
112
+ * @override
110
113
  */
111
114
  isEnded() {
112
115
  if (this.ad && this.ad.isLinear()) {