shaka-player 4.11.13 → 4.12.1

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 (71) hide show
  1. package/README.md +47 -0
  2. package/dist/deps.js +8 -8
  3. package/dist/locales.js +35 -35
  4. package/dist/shaka-player.compiled.d.ts +36 -13
  5. package/dist/shaka-player.compiled.debug.d.ts +36 -13
  6. package/dist/shaka-player.compiled.debug.externs.js +46 -11
  7. package/dist/shaka-player.compiled.debug.js +543 -517
  8. package/dist/shaka-player.compiled.debug.map +4 -4
  9. package/dist/shaka-player.compiled.externs.js +46 -11
  10. package/dist/shaka-player.compiled.js +1348 -1331
  11. package/dist/shaka-player.compiled.map +4 -4
  12. package/dist/shaka-player.ui.d.ts +37 -14
  13. package/dist/shaka-player.ui.debug.d.ts +37 -14
  14. package/dist/shaka-player.ui.debug.externs.js +46 -11
  15. package/dist/shaka-player.ui.debug.js +629 -598
  16. package/dist/shaka-player.ui.debug.map +4 -4
  17. package/dist/shaka-player.ui.externs.js +46 -11
  18. package/dist/shaka-player.ui.js +1624 -1603
  19. package/dist/shaka-player.ui.map +4 -4
  20. package/externs/shaka/ads.js +9 -0
  21. package/externs/shaka/manifest.js +26 -1
  22. package/externs/shaka/offline.js +8 -2
  23. package/externs/shaka/player.js +80 -28
  24. package/externs/shaka/text.js +9 -0
  25. package/lib/ads/ad_manager.js +6 -0
  26. package/lib/ads/ad_utils.js +1 -0
  27. package/lib/ads/client_side_ad.js +8 -0
  28. package/lib/ads/interstitial_ad.js +25 -4
  29. package/lib/ads/interstitial_ad_manager.js +67 -8
  30. package/lib/ads/media_tailor_ad.js +8 -0
  31. package/lib/ads/server_side_ad.js +8 -0
  32. package/lib/dash/content_protection.js +31 -0
  33. package/lib/dash/dash_parser.js +22 -12
  34. package/lib/hls/hls_parser.js +63 -49
  35. package/lib/media/adaptation_set.js +11 -17
  36. package/lib/media/adaptation_set_criteria.js +4 -9
  37. package/lib/media/drm_engine.js +3 -1
  38. package/lib/media/manifest_filterer.js +2 -1
  39. package/lib/media/media_source_engine.js +286 -20
  40. package/lib/media/playhead.js +3 -1
  41. package/lib/media/preload_manager.js +10 -7
  42. package/lib/media/segment_prefetch.js +32 -13
  43. package/lib/media/segment_reference.js +3 -3
  44. package/lib/media/streaming_engine.js +87 -261
  45. package/lib/mss/mss_parser.js +1 -0
  46. package/lib/offline/download_info.js +5 -1
  47. package/lib/offline/indexeddb/storage_mechanism.js +4 -3
  48. package/lib/offline/indexeddb/v1_storage_cell.js +2 -0
  49. package/lib/offline/indexeddb/v2_storage_cell.js +2 -0
  50. package/lib/offline/manifest_converter.js +4 -0
  51. package/lib/offline/storage.js +277 -5
  52. package/lib/player.js +224 -78
  53. package/lib/text/simple_text_displayer.js +7 -0
  54. package/lib/text/stub_text_displayer.js +7 -0
  55. package/lib/text/ui_text_displayer.js +12 -0
  56. package/lib/util/dom_utils.js +14 -0
  57. package/lib/util/error.js +5 -0
  58. package/lib/util/periods.js +2 -0
  59. package/lib/util/platform.js +15 -0
  60. package/lib/util/player_configuration.js +11 -4
  61. package/lib/util/stream_utils.js +20 -1
  62. package/package.json +1 -1
  63. package/ui/ad_statistics_button.js +12 -0
  64. package/ui/controls.js +31 -7
  65. package/ui/externs/ui.js +8 -1
  66. package/ui/fullscreen_button.js +9 -0
  67. package/ui/locales/be.json +49 -0
  68. package/ui/mute_button.js +42 -11
  69. package/ui/skip_ad_button.js +16 -11
  70. package/ui/statistics_button.js +12 -0
  71. package/ui/ui.js +10 -5
@@ -11,6 +11,8 @@ goog.require('shaka.Player');
11
11
  goog.require('shaka.log');
12
12
  goog.require('shaka.media.DrmEngine');
13
13
  goog.require('shaka.media.ManifestParser');
14
+ goog.require('shaka.media.SegmentIndex');
15
+ goog.require('shaka.media.SegmentReference');
14
16
  goog.require('shaka.net.NetworkingEngine');
15
17
  goog.require('shaka.net.NetworkingUtils');
16
18
  goog.require('shaka.offline.DownloadInfo');
@@ -20,13 +22,16 @@ goog.require('shaka.offline.SessionDeleter');
20
22
  goog.require('shaka.offline.StorageMuxer');
21
23
  goog.require('shaka.offline.StoredContentUtils');
22
24
  goog.require('shaka.offline.StreamBandwidthEstimator');
25
+ goog.require('shaka.text.TextEngine');
23
26
  goog.require('shaka.util.AbortableOperation');
24
27
  goog.require('shaka.util.ArrayUtils');
28
+ goog.require('shaka.util.BufferUtils');
25
29
  goog.require('shaka.util.ConfigUtils');
26
30
  goog.require('shaka.util.Destroyer');
27
31
  goog.require('shaka.util.Error');
28
32
  goog.require('shaka.util.IDestroyable');
29
33
  goog.require('shaka.util.Iterables');
34
+ goog.require('shaka.util.ManifestParserUtils');
30
35
  goog.require('shaka.util.MimeUtils');
31
36
  goog.require('shaka.util.Platform');
32
37
  goog.require('shaka.util.PlayerConfiguration');
@@ -142,6 +147,13 @@ shaka.offline.Storage = class {
142
147
  this.config_ = null;
143
148
  this.networkingEngine_ = null;
144
149
  });
150
+
151
+ /**
152
+ * Contains an ID for use with creating streams. The manifest parser should
153
+ * start with small IDs, so this starts with a large one.
154
+ * @private {number}
155
+ */
156
+ this.nextExternalStreamId_ = 1e9;
145
157
  }
146
158
 
147
159
 
@@ -249,8 +261,12 @@ shaka.offline.Storage = class {
249
261
  * application-specific metadata you need associated with the stored
250
262
  * content. For details on the data types that can be stored here, please
251
263
  * refer to {@link https://bit.ly/StructClone}
252
- * @param {string=} mimeType
264
+ * @param {?string=} mimeType
253
265
  * The mime type for the content |manifestUri| points to.
266
+ * @param {?Array.<string>=} externalThumbnails
267
+ * The external thumbnails to store along the main content.
268
+ * @param {?Array.<shaka.extern.ExtraText>=} externalText
269
+ * The external text to store along the main content.
254
270
  * @return {!shaka.extern.IAbortableOperation.<shaka.extern.StoredContent>}
255
271
  * An AbortableOperation that resolves with a structure representing what
256
272
  * was stored. The "offlineUri" member is the URI that should be given to
@@ -260,7 +276,7 @@ shaka.offline.Storage = class {
260
276
  * AbortableOperation.
261
277
  * @export
262
278
  */
263
- store(uri, appMetadata, mimeType) {
279
+ store(uri, appMetadata, mimeType, externalThumbnails, externalText) {
264
280
  goog.asserts.assert(
265
281
  this.networkingEngine_,
266
282
  'Cannot call |store| after calling |destroy|.');
@@ -290,7 +306,8 @@ shaka.offline.Storage = class {
290
306
  this.openDownloadManagers_.push(downloader);
291
307
 
292
308
  const storeOp = this.store_(
293
- uri, appMetadata || {}, getParser, config, downloader);
309
+ uri, appMetadata || {}, externalThumbnails || [], externalText || [],
310
+ getParser, config, downloader);
294
311
  const abortableStoreOp = new shaka.util.AbortableOperation(storeOp, () => {
295
312
  return downloader.abortAll();
296
313
  });
@@ -306,13 +323,16 @@ shaka.offline.Storage = class {
306
323
  *
307
324
  * @param {string} uri
308
325
  * @param {!Object} appMetadata
326
+ * @param {!Array.<string>} externalThumbnails
327
+ * @param {!Array.<shaka.extern.ExtraText>} externalText
309
328
  * @param {function():!Promise.<shaka.extern.ManifestParser>} getParser
310
329
  * @param {shaka.extern.PlayerConfiguration} config
311
330
  * @param {!shaka.offline.DownloadManager} downloader
312
331
  * @return {!Promise.<shaka.extern.StoredContent>}
313
332
  * @private
314
333
  */
315
- async store_(uri, appMetadata, getParser, config, downloader) {
334
+ async store_(uri, appMetadata, externalThumbnails, externalText,
335
+ getParser, config, downloader) {
316
336
  this.requireSupport_();
317
337
 
318
338
  // Since we will need to use |parser|, |drmEngine|, |activeHandle|, and
@@ -357,6 +377,23 @@ shaka.offline.Storage = class {
357
377
  uri);
358
378
  }
359
379
 
380
+ for (const thumbnailUri of externalThumbnails) {
381
+ const imageStream =
382
+ // eslint-disable-next-line no-await-in-loop
383
+ await this.createExternalImageStream_(thumbnailUri, manifest);
384
+ manifest.imageStreams.push(imageStream);
385
+ this.ensureNotDestroyed_();
386
+ }
387
+
388
+ for (const text of externalText) {
389
+ const textStream =
390
+ // eslint-disable-next-line no-await-in-loop
391
+ await this.createExternalTextStream_(manifest,
392
+ text.uri, text.language, text.kind, text.mime, text.codecs);
393
+ manifest.textStreams.push(textStream);
394
+ this.ensureNotDestroyed_();
395
+ }
396
+
360
397
  // Create the DRM engine, and load the keys in the manifest.
361
398
  drmEngine = await this.createDrmEngine(
362
399
  manifest,
@@ -674,10 +711,11 @@ shaka.offline.Storage = class {
674
711
  const preferredDecodingAttributes = config.preferredDecodingAttributes;
675
712
  const preferredVideoCodecs = config.preferredVideoCodecs;
676
713
  const preferredAudioCodecs = config.preferredAudioCodecs;
714
+ const preferredTextFormats = config.preferredTextFormats;
677
715
 
678
716
  shaka.util.StreamUtils.chooseCodecsAndFilterManifest(
679
717
  manifest, preferredVideoCodecs, preferredAudioCodecs,
680
- preferredDecodingAttributes);
718
+ preferredDecodingAttributes, preferredTextFormats);
681
719
 
682
720
  for (const variant of manifest.variants) {
683
721
  goog.asserts.assert(
@@ -1216,6 +1254,238 @@ shaka.offline.Storage = class {
1216
1254
  return manifest;
1217
1255
  }
1218
1256
 
1257
+ /**
1258
+ * @param {string} uri
1259
+ * @param {shaka.extern.Manifest} manifest
1260
+ * @return {!Promise.<shaka.extern.Stream>}
1261
+ * @private
1262
+ */
1263
+ async createExternalImageStream_(uri, manifest) {
1264
+ const mimeType = await this.getTextMimetype_(uri);
1265
+
1266
+ if (mimeType != 'text/vtt') {
1267
+ throw new shaka.util.Error(
1268
+ shaka.util.Error.Severity.RECOVERABLE,
1269
+ shaka.util.Error.Category.TEXT,
1270
+ shaka.util.Error.Code.UNSUPPORTED_EXTERNAL_THUMBNAILS_URI,
1271
+ uri);
1272
+ }
1273
+
1274
+ goog.asserts.assert(
1275
+ this.networkingEngine_, 'Need networking engine.');
1276
+ const buffer = await this.getTextData_(uri,
1277
+ this.networkingEngine_,
1278
+ this.config_.streaming.retryParameters);
1279
+
1280
+ const factory = shaka.text.TextEngine.findParser(mimeType);
1281
+ if (!factory) {
1282
+ throw new shaka.util.Error(
1283
+ shaka.util.Error.Severity.CRITICAL,
1284
+ shaka.util.Error.Category.TEXT,
1285
+ shaka.util.Error.Code.MISSING_TEXT_PLUGIN,
1286
+ mimeType);
1287
+ }
1288
+ const TextParser = factory();
1289
+ const time = {
1290
+ periodStart: 0,
1291
+ segmentStart: 0,
1292
+ segmentEnd: manifest.presentationTimeline.getDuration(),
1293
+ vttOffset: 0,
1294
+ };
1295
+ const data = shaka.util.BufferUtils.toUint8(buffer);
1296
+ const cues = TextParser.parseMedia(data, time, uri, /* images= */ []);
1297
+
1298
+ const references = [];
1299
+ for (const cue of cues) {
1300
+ let uris = null;
1301
+ const getUris = () => {
1302
+ if (uris == null) {
1303
+ uris = shaka.util.ManifestParserUtils.resolveUris(
1304
+ [uri], [cue.payload]);
1305
+ }
1306
+ return uris || [];
1307
+ };
1308
+ const reference = new shaka.media.SegmentReference(
1309
+ cue.startTime,
1310
+ cue.endTime,
1311
+ getUris,
1312
+ /* startByte= */ 0,
1313
+ /* endByte= */ null,
1314
+ /* initSegmentReference= */ null,
1315
+ /* timestampOffset= */ 0,
1316
+ /* appendWindowStart= */ 0,
1317
+ /* appendWindowEnd= */ Infinity,
1318
+ );
1319
+ if (cue.payload.includes('#xywh')) {
1320
+ const spriteInfo = cue.payload.split('#xywh=')[1].split(',');
1321
+ if (spriteInfo.length === 4) {
1322
+ reference.setThumbnailSprite({
1323
+ height: parseInt(spriteInfo[3], 10),
1324
+ positionX: parseInt(spriteInfo[0], 10),
1325
+ positionY: parseInt(spriteInfo[1], 10),
1326
+ width: parseInt(spriteInfo[2], 10),
1327
+ });
1328
+ }
1329
+ }
1330
+ references.push(reference);
1331
+ }
1332
+
1333
+ let segmentMimeType = mimeType;
1334
+ if (references.length) {
1335
+ segmentMimeType = await shaka.net.NetworkingUtils.getMimeType(
1336
+ references[0].getUris()[0],
1337
+ this.networkingEngine_, this.config_.manifest.retryParameters);
1338
+ }
1339
+
1340
+ return {
1341
+ id: this.nextExternalStreamId_++,
1342
+ originalId: null,
1343
+ groupId: null,
1344
+ createSegmentIndex: () => Promise.resolve(),
1345
+ segmentIndex: new shaka.media.SegmentIndex(references),
1346
+ mimeType: segmentMimeType || '',
1347
+ codecs: '',
1348
+ kind: '',
1349
+ encrypted: false,
1350
+ drmInfos: [],
1351
+ keyIds: new Set(),
1352
+ language: 'und',
1353
+ originalLanguage: null,
1354
+ label: null,
1355
+ type: shaka.util.ManifestParserUtils.ContentType.IMAGE,
1356
+ primary: false,
1357
+ trickModeVideo: null,
1358
+ emsgSchemeIdUris: null,
1359
+ roles: [],
1360
+ forced: false,
1361
+ channelsCount: null,
1362
+ audioSamplingRate: null,
1363
+ spatialAudio: false,
1364
+ closedCaptions: null,
1365
+ tilesLayout: '1x1',
1366
+ accessibilityPurpose: null,
1367
+ external: true,
1368
+ fastSwitching: false,
1369
+ fullMimeTypes: new Set([shaka.util.MimeUtils.getFullType(
1370
+ segmentMimeType || '', '')]),
1371
+ isAudioMuxedInVideo: false,
1372
+ };
1373
+ }
1374
+
1375
+ /**
1376
+ * @param {shaka.extern.Manifest} manifest
1377
+ * @param {string} uri
1378
+ * @param {string} language
1379
+ * @param {string} kind
1380
+ * @param {string=} mimeType
1381
+ * @param {string=} codec
1382
+ * @private
1383
+ */
1384
+ async createExternalTextStream_(manifest, uri, language, kind, mimeType,
1385
+ codec) {
1386
+ if (!mimeType) {
1387
+ mimeType = await this.getTextMimetype_(uri);
1388
+ }
1389
+
1390
+ /** @type {shaka.extern.Stream} */
1391
+ const stream = {
1392
+ id: this.nextExternalStreamId_++,
1393
+ originalId: null,
1394
+ groupId: null,
1395
+ createSegmentIndex: () => Promise.resolve(),
1396
+ segmentIndex: shaka.media.SegmentIndex.forSingleSegment(
1397
+ /* startTime= */ 0,
1398
+ /* duration= */ manifest.presentationTimeline.getDuration(),
1399
+ /* uris= */ [uri]),
1400
+ mimeType: mimeType || '',
1401
+ codecs: codec || '',
1402
+ kind: kind,
1403
+ encrypted: false,
1404
+ drmInfos: [],
1405
+ keyIds: new Set(),
1406
+ language: language,
1407
+ originalLanguage: language,
1408
+ label: null,
1409
+ type: shaka.util.ManifestParserUtils.ContentType.TEXT,
1410
+ primary: false,
1411
+ trickModeVideo: null,
1412
+ emsgSchemeIdUris: null,
1413
+ roles: [],
1414
+ forced: false,
1415
+ channelsCount: null,
1416
+ audioSamplingRate: null,
1417
+ spatialAudio: false,
1418
+ closedCaptions: null,
1419
+ accessibilityPurpose: null,
1420
+ external: true,
1421
+ fastSwitching: false,
1422
+ fullMimeTypes: new Set([shaka.util.MimeUtils.getFullType(
1423
+ mimeType || '', codec || '')]),
1424
+ isAudioMuxedInVideo: false,
1425
+ };
1426
+
1427
+ const fullMimeType = shaka.util.MimeUtils.getFullType(
1428
+ stream.mimeType, stream.codecs);
1429
+ const supported = shaka.text.TextEngine.isTypeSupported(fullMimeType);
1430
+ if (!supported) {
1431
+ throw new shaka.util.Error(
1432
+ shaka.util.Error.Severity.CRITICAL,
1433
+ shaka.util.Error.Category.TEXT,
1434
+ shaka.util.Error.Code.MISSING_TEXT_PLUGIN,
1435
+ mimeType);
1436
+ }
1437
+
1438
+ return stream;
1439
+ }
1440
+
1441
+ /**
1442
+ * @param {string} uri
1443
+ * @return {!Promise.<string>}
1444
+ * @private
1445
+ */
1446
+ async getTextMimetype_(uri) {
1447
+ let mimeType;
1448
+ try {
1449
+ goog.asserts.assert(
1450
+ this.networkingEngine_, 'Need networking engine.');
1451
+ // eslint-disable-next-line require-atomic-updates
1452
+ mimeType = await shaka.net.NetworkingUtils.getMimeType(uri,
1453
+ this.networkingEngine_,
1454
+ this.config_.streaming.retryParameters);
1455
+ } catch (error) {}
1456
+
1457
+ if (mimeType) {
1458
+ return mimeType;
1459
+ }
1460
+
1461
+ shaka.log.error(
1462
+ 'The mimeType has not been provided and it could not be deduced ' +
1463
+ 'from its uri.');
1464
+ throw new shaka.util.Error(
1465
+ shaka.util.Error.Severity.RECOVERABLE,
1466
+ shaka.util.Error.Category.TEXT,
1467
+ shaka.util.Error.Code.TEXT_COULD_NOT_GUESS_MIME_TYPE,
1468
+ uri);
1469
+ }
1470
+
1471
+ /**
1472
+ * @param {string} uri
1473
+ * @param {!shaka.net.NetworkingEngine} netEngine
1474
+ * @param {shaka.extern.RetryParameters} retryParams
1475
+ * @return {!Promise.<BufferSource>}
1476
+ * @private
1477
+ */
1478
+ async getTextData_(uri, netEngine, retryParams) {
1479
+ const type = shaka.net.NetworkingEngine.RequestType.SEGMENT;
1480
+
1481
+ const request = shaka.net.NetworkingEngine.makeRequest([uri], retryParams);
1482
+ request.method = 'GET';
1483
+
1484
+ const response = await netEngine.request(type, request).promise;
1485
+
1486
+ return response.data;
1487
+ }
1488
+
1219
1489
  /**
1220
1490
  * This method is public so that it can be override in testing.
1221
1491
  *
@@ -1340,6 +1610,7 @@ shaka.offline.Storage = class {
1340
1610
  tilesLayout: stream.tilesLayout,
1341
1611
  external: stream.external,
1342
1612
  fastSwitching: stream.fastSwitching,
1613
+ isAudioMuxedInVideo: stream.isAudioMuxedInVideo,
1343
1614
  };
1344
1615
 
1345
1616
  const startTime =
@@ -1396,6 +1667,7 @@ shaka.offline.Storage = class {
1396
1667
  dataKey: 0,
1397
1668
  mimeType: segment.mimeType,
1398
1669
  codecs: segment.codecs,
1670
+ thumbnailSprite: segment.thumbnailSprite,
1399
1671
  };
1400
1672
  streamDb.segments.push(segmentDB);
1401
1673
  if (numberOfParallelDownloads !== 0) {