shaka-player 4.9.7 → 4.9.9

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.
@@ -164,53 +164,62 @@ shaka.cea.Mp4CeaParser = class {
164
164
  /** @type {!Array<!shaka.extern.ICeaParser.CaptionPacket>} **/
165
165
  const captionPackets = [];
166
166
 
167
- // Fields that are found in MOOF boxes
168
- let defaultSampleDuration = this.defaultSampleDuration_;
169
- let defaultSampleSize = this.defaultSampleSize_;
170
167
  let moofOffset = 0;
171
- /** @type {!Array<shaka.util.ParsedTRUNBox>} */
172
- let parsedTRUNs = [];
173
- let baseMediaDecodeTime = null;
174
- let timescale = shaka.cea.CeaUtils.DEFAULT_TIMESCALE_VALUE;
168
+
169
+ /** @type {!Array<!shaka.cea.Mp4CeaParser.ParsedTRAF>} */
170
+ let parsedTRAFs = [];
175
171
 
176
172
  new Mp4Parser()
177
173
  .box('moof', (box) => {
178
174
  moofOffset = box.start;
179
- // trun box parsing is reset on each moof.
180
- parsedTRUNs = [];
175
+ // traf box parsing is reset on each moof.
176
+ parsedTRAFs = [];
177
+ Mp4Parser.children(box);
178
+ })
179
+ .box('traf', (box) => {
180
+ parsedTRAFs.push({
181
+ baseMediaDecodeTime: null,
182
+ defaultSampleDuration: this.defaultSampleDuration_,
183
+ defaultSampleSize: this.defaultSampleSize_,
184
+ parsedTRUNs: [],
185
+ timescale: shaka.cea.CeaUtils.DEFAULT_TIMESCALE_VALUE,
186
+ });
181
187
  Mp4Parser.children(box);
182
188
  })
183
- .box('traf', Mp4Parser.children)
184
189
  .fullBox('trun', (box) => {
185
190
  goog.asserts.assert(
186
- box.version != null && box.flags!=null,
191
+ box.version != null && box.flags != null,
187
192
  'TRUN is a full box and should have a valid version & flags.');
188
193
 
194
+ const lastTRAF = parsedTRAFs[parsedTRAFs.length - 1];
195
+
189
196
  const parsedTRUN = shaka.util.Mp4BoxParsers.parseTRUN(
190
197
  box.reader, box.version, box.flags);
191
- parsedTRUNs.push(parsedTRUN);
198
+ lastTRAF.parsedTRUNs.push(parsedTRUN);
192
199
  })
193
200
  .fullBox('tfhd', (box) => {
194
201
  goog.asserts.assert(
195
202
  box.flags != null,
196
203
  'TFHD is a full box and should have valid flags.');
197
204
 
205
+ const lastTRAF = parsedTRAFs[parsedTRAFs.length - 1];
206
+
198
207
  const parsedTFHD = shaka.util.Mp4BoxParsers.parseTFHD(
199
208
  box.reader, box.flags);
200
209
 
201
210
  // If specified, defaultSampleDuration and defaultSampleSize
202
211
  // override the ones specified in the TREX box
203
- defaultSampleDuration = parsedTFHD.defaultSampleDuration ||
212
+ lastTRAF.defaultSampleDuration = parsedTFHD.defaultSampleDuration ||
204
213
  this.defaultSampleDuration_;
205
214
 
206
- defaultSampleSize = parsedTFHD.defaultSampleSize ||
215
+ lastTRAF.defaultSampleSize = parsedTFHD.defaultSampleSize ||
207
216
  this.defaultSampleSize_;
208
217
 
209
218
  const trackId = parsedTFHD.trackId;
210
219
 
211
220
  // Get the timescale from the track Id
212
221
  if (this.trackIdToTimescale_.has(trackId)) {
213
- timescale = this.trackIdToTimescale_.get(trackId);
222
+ lastTRAF.timescale = this.trackIdToTimescale_.get(trackId);
214
223
  }
215
224
  })
216
225
  .fullBox('tfdt', (box) => {
@@ -218,27 +227,37 @@ shaka.cea.Mp4CeaParser = class {
218
227
  box.version != null,
219
228
  'TFDT is a full box and should have a valid version.');
220
229
 
230
+ const lastTRAF = parsedTRAFs[parsedTRAFs.length - 1];
231
+
221
232
  const parsedTFDT = shaka.util.Mp4BoxParsers.parseTFDTInaccurate(
222
233
  box.reader, box.version);
223
234
 
224
- baseMediaDecodeTime = parsedTFDT.baseMediaDecodeTime;
235
+ lastTRAF.baseMediaDecodeTime = parsedTFDT.baseMediaDecodeTime;
225
236
  })
226
237
  .box('mdat', (box) => {
227
- if (baseMediaDecodeTime === null) {
228
- // This field should have been populated by the Base Media Decode
229
- // Time in the tfdt box.
230
- shaka.log.alwaysWarn(
231
- 'Unable to find base media decode time for CEA captions!');
232
- throw new shaka.util.Error(
233
- shaka.util.Error.Severity.CRITICAL,
234
- shaka.util.Error.Category.TEXT,
235
- shaka.util.Error.Code.INVALID_MP4_CEA);
236
- }
237
-
238
238
  const offset = moofOffset - box.start - 8;
239
- this.parseMdat_(box.reader, baseMediaDecodeTime, timescale,
240
- defaultSampleDuration, defaultSampleSize, offset, parsedTRUNs,
241
- captionPackets);
239
+ const initialPosition = box.reader.getPosition();
240
+ for (const parsedTRAF of parsedTRAFs) {
241
+ if (parsedTRAF.baseMediaDecodeTime === null) {
242
+ // This field should have been populated by the Base Media Decode
243
+ // Time in the tfdt box.
244
+ shaka.log.alwaysWarn(
245
+ 'Unable to find base media decode time for CEA captions!');
246
+ throw new shaka.util.Error(
247
+ shaka.util.Error.Severity.CRITICAL,
248
+ shaka.util.Error.Category.TEXT,
249
+ shaka.util.Error.Code.INVALID_MP4_CEA);
250
+ }
251
+ box.reader.seek(initialPosition);
252
+ this.parseMdat_(box.reader,
253
+ parsedTRAF.baseMediaDecodeTime,
254
+ parsedTRAF.timescale,
255
+ parsedTRAF.defaultSampleDuration,
256
+ parsedTRAF.defaultSampleSize,
257
+ offset,
258
+ parsedTRAF.parsedTRUNs,
259
+ captionPackets);
260
+ }
242
261
  })
243
262
  .parse(mediaSegment, /* partialOkay= */ false);
244
263
 
@@ -315,7 +334,7 @@ shaka.cea.Mp4CeaParser = class {
315
334
  timeOffset = sampleData[sampleIndex].sampleCompositionTimeOffset || 0;
316
335
  }
317
336
 
318
- const pts = (time + timeOffset)/timescale;
337
+ const pts = (time + timeOffset) / timescale;
319
338
  for (const packet of this.seiProcessor_
320
339
  .process(reader.readBytes(naluSize - naluHeaderSize))) {
321
340
  captionPackets.push({
@@ -384,5 +403,22 @@ shaka.cea.Mp4CeaParser.CodecBitstreamMap_ = {
384
403
  'dvhe': shaka.cea.Mp4CeaParser.BitstreamFormat.H265,
385
404
  };
386
405
 
406
+ /**
407
+ * @typedef {{
408
+ * baseMediaDecodeTime: ?number,
409
+ * defaultSampleDuration: number,
410
+ * defaultSampleSize: number,
411
+ * parsedTRUNs: !Array<shaka.util.ParsedTRUNBox>,
412
+ * timescale: number
413
+ * }}
414
+ *
415
+ * @property {?number} baseMediaDecodeTime
416
+ * @property {number} defaultSampleDuration
417
+ * @property {number} defaultSampleSize
418
+ * @property {!Array<shaka.util.ParsedTRUNBox>} parsedTRUNs
419
+ * @property {?number} timescale
420
+ */
421
+ shaka.cea.Mp4CeaParser.ParsedTRAF;
422
+
387
423
  shaka.media.ClosedCaptionParser.registerParser('video/mp4',
388
424
  () => new shaka.cea.Mp4CeaParser());
@@ -2319,24 +2319,32 @@ shaka.hls.HlsParser = class {
2319
2319
  this.config_.hls.disableCodecGuessing) ||
2320
2320
  (this.needsClosedCaptionsDetection_ && type == ContentType.VIDEO &&
2321
2321
  !this.config_.hls.disableClosedCaptionsDetection)) {
2322
- this.needsClosedCaptionsDetection_ = false;
2323
-
2324
- const basicInfo = await this.getMediaPlaylistBasicInfo_(
2325
- playlist, getUris, mediaVariables);
2326
-
2327
- goog.asserts.assert(
2328
- type === basicInfo.type, 'Media types should match!');
2329
-
2330
- if (basicInfo.closedCaptions.size && (!closedCaptions ||
2331
- closedCaptions.size != basicInfo.closedCaptions.size)) {
2332
- closedCaptions = basicInfo.closedCaptions;
2333
- closedCaptionsUpdated = true;
2322
+ let canRequestBasicInfo = playlist.segments.length > 0;
2323
+ if (canRequestBasicInfo) {
2324
+ const segment = playlist.segments[0];
2325
+ if (shaka.hls.Utils.getFirstTagWithName(segment.tags, 'EXT-X-GAP')) {
2326
+ canRequestBasicInfo = false;
2327
+ }
2334
2328
  }
2329
+ if (canRequestBasicInfo) {
2330
+ this.needsClosedCaptionsDetection_ = false;
2331
+ const basicInfo = await this.getMediaPlaylistBasicInfo_(
2332
+ playlist, getUris, mediaVariables);
2333
+
2334
+ goog.asserts.assert(
2335
+ type === basicInfo.type, 'Media types should match!');
2336
+
2337
+ if (basicInfo.closedCaptions.size && (!closedCaptions ||
2338
+ closedCaptions.size != basicInfo.closedCaptions.size)) {
2339
+ closedCaptions = basicInfo.closedCaptions;
2340
+ closedCaptionsUpdated = true;
2341
+ }
2335
2342
 
2336
- if (!this.codecInfoInManifest_ &&
2337
- this.config_.hls.disableCodecGuessing) {
2338
- mimeType = basicInfo.mimeType;
2339
- codecs = basicInfo.codecs;
2343
+ if (!this.codecInfoInManifest_ &&
2344
+ this.config_.hls.disableCodecGuessing) {
2345
+ mimeType = basicInfo.mimeType;
2346
+ codecs = basicInfo.codecs;
2347
+ }
2340
2348
  }
2341
2349
  }
2342
2350
 
@@ -3944,9 +3952,14 @@ shaka.hls.HlsParser = class {
3944
3952
  'Playlist should have segments!');
3945
3953
  const middleSegmentIdx = Math.trunc((playlist.segments.length - 1) / 2);
3946
3954
 
3955
+ const middleSegment = playlist.segments[middleSegmentIdx];
3956
+ if (shaka.hls.Utils.getFirstTagWithName(middleSegment.tags, 'EXT-X-GAP')) {
3957
+ return this.guessMimeTypeFallback_(contentType);
3958
+ }
3959
+
3947
3960
  const middleSegmentUris = shaka.hls.Utils.constructSegmentUris(
3948
3961
  getUris(),
3949
- playlist.segments[middleSegmentIdx].verbatimSegmentUri,
3962
+ middleSegment.verbatimSegmentUri,
3950
3963
  variables);
3951
3964
 
3952
3965
  const parsedUri = new goog.Uri(middleSegmentUris[0]);
@@ -312,4 +312,5 @@ shaka.hls.ManifestTextParser.SEGMENT_TAGS = [
312
312
  'EXT-X-KEY',
313
313
  'EXT-X-DATERANGE',
314
314
  'EXT-X-MAP',
315
+ 'EXT-X-GAP',
315
316
  ];
@@ -140,7 +140,7 @@ shaka.media.SegmentUtils = class {
140
140
  const SegmentUtils = shaka.media.SegmentUtils;
141
141
 
142
142
  const audioCodecs = [];
143
- const videoCodecs = [];
143
+ let videoCodecs = [];
144
144
 
145
145
  let hasAudio = false;
146
146
  let hasVideo = false;
@@ -179,6 +179,7 @@ shaka.media.SegmentUtils = class {
179
179
  break;
180
180
  case 'ac-3':
181
181
  case 'ec-3':
182
+ case 'ac-4':
182
183
  case 'opus':
183
184
  case 'flac':
184
185
  audioCodecs.push(codecLC);
@@ -207,6 +208,19 @@ shaka.media.SegmentUtils = class {
207
208
  /** @type {?string} */
208
209
  let baseBox;
209
210
 
211
+ const genericAudioBox = (box) => {
212
+ const parsedAudioSampleEntryBox =
213
+ shaka.util.Mp4BoxParsers.audioSampleEntry(box.reader);
214
+ channelCount = parsedAudioSampleEntryBox.channelCount;
215
+ sampleRate = parsedAudioSampleEntryBox.sampleRate;
216
+ codecBoxParser(box);
217
+ };
218
+
219
+ const genericVideoBox = (box) => {
220
+ baseBox = box.name;
221
+ Mp4Parser.visualSampleEntry(box);
222
+ };
223
+
210
224
  new Mp4Parser()
211
225
  .box('moov', Mp4Parser.children)
212
226
  .box('trak', Mp4Parser.children)
@@ -235,9 +249,10 @@ shaka.media.SegmentUtils = class {
235
249
  // AUDIO
236
250
  // These are the various boxes that signal a codec.
237
251
  .box('mp4a', (box) => {
238
- const parsedMP4ABox = shaka.util.Mp4BoxParsers.parseMP4A(box.reader);
239
- channelCount = parsedMP4ABox.channelCount;
240
- sampleRate = parsedMP4ABox.sampleRate;
252
+ const parsedAudioSampleEntryBox =
253
+ shaka.util.Mp4BoxParsers.audioSampleEntry(box.reader);
254
+ channelCount = parsedAudioSampleEntryBox.channelCount;
255
+ sampleRate = parsedAudioSampleEntryBox.sampleRate;
241
256
  if (box.reader.hasMoreData()) {
242
257
  Mp4Parser.children(box);
243
258
  } else {
@@ -249,54 +264,24 @@ shaka.media.SegmentUtils = class {
249
264
  audioCodecs.push(parsedESDSBox.codec);
250
265
  hasAudio = true;
251
266
  })
252
- .box('ac-3', codecBoxParser)
253
- .box('ec-3', codecBoxParser)
254
- .box('opus', codecBoxParser)
255
- .box('Opus', codecBoxParser)
256
- .box('fLaC', codecBoxParser)
267
+ .box('ac-3', genericAudioBox)
268
+ .box('ec-3', genericAudioBox)
269
+ .box('ac-4', genericAudioBox)
270
+ .box('Opus', genericAudioBox)
271
+ .box('fLaC', genericAudioBox)
257
272
 
258
273
  // VIDEO
259
274
  // These are the various boxes that signal a codec.
260
- .box('avc1', (box) => {
261
- baseBox = box.name;
262
- Mp4Parser.visualSampleEntry(box);
263
- })
264
- .box('avc3', (box) => {
265
- baseBox = box.name;
266
- Mp4Parser.visualSampleEntry(box);
267
- })
268
- .box('hev1', (box) => {
269
- baseBox = box.name;
270
- Mp4Parser.visualSampleEntry(box);
271
- })
272
- .box('hvc1', (box) => {
273
- baseBox = box.name;
274
- Mp4Parser.visualSampleEntry(box);
275
- })
276
- .box('dva1', (box) => {
277
- baseBox = box.name;
278
- Mp4Parser.visualSampleEntry(box);
279
- })
280
- .box('dvav', (box) => {
281
- baseBox = box.name;
282
- Mp4Parser.visualSampleEntry(box);
283
- })
284
- .box('dvh1', (box) => {
285
- baseBox = box.name;
286
- Mp4Parser.visualSampleEntry(box);
287
- })
288
- .box('dvhe', (box) => {
289
- baseBox = box.name;
290
- Mp4Parser.visualSampleEntry(box);
291
- })
292
- .box('vp09', (box) => {
293
- baseBox = box.name;
294
- Mp4Parser.visualSampleEntry(box);
295
- })
296
- .box('av01', (box) => {
297
- baseBox = box.name;
298
- Mp4Parser.visualSampleEntry(box);
299
- })
275
+ .box('avc1', genericVideoBox)
276
+ .box('avc3', genericVideoBox)
277
+ .box('hev1', genericVideoBox)
278
+ .box('hvc1', genericVideoBox)
279
+ .box('dva1', genericVideoBox)
280
+ .box('dvav', genericVideoBox)
281
+ .box('dvh1', genericVideoBox)
282
+ .box('dvhe', genericVideoBox)
283
+ .box('vp09', genericVideoBox)
284
+ .box('av01', genericVideoBox)
300
285
  .box('avcC', (box) => {
301
286
  let codecBase = baseBox || '';
302
287
  switch (baseBox) {
@@ -375,6 +360,13 @@ shaka.media.SegmentUtils = class {
375
360
  })
376
361
 
377
362
  .box('colr', (box) => {
363
+ videoCodecs = videoCodecs.map((codec) => {
364
+ if (codec.startsWith('av01.')) {
365
+ return shaka.util.Mp4BoxParsers.updateAV1CodecWithCOLRBox(
366
+ codec, box.reader);
367
+ }
368
+ return codec;
369
+ });
378
370
  const {videoRange, colorGamut} =
379
371
  shaka.util.Mp4BoxParsers.parseCOLR(box.reader);
380
372
  realVideoRange = videoRange;
@@ -134,6 +134,12 @@ shaka.media.StreamingEngine = class {
134
134
  projection: null,
135
135
  hfov: null,
136
136
  };
137
+
138
+ /** @private {number} */
139
+ this.playRangeStart_ = 0;
140
+
141
+ /** @private {number} */
142
+ this.playRangeEnd_ = Infinity;
137
143
  }
138
144
 
139
145
  /** @override */
@@ -251,6 +257,20 @@ shaka.media.StreamingEngine = class {
251
257
  }
252
258
 
253
259
 
260
+ /**
261
+ * Applies a playback range. This will only affect non-live content.
262
+ *
263
+ * @param {number} playRangeStart
264
+ * @param {number} playRangeEnd
265
+ */
266
+ applyPlayRange(playRangeStart, playRangeEnd) {
267
+ if (!this.manifest_.presentationTimeline.isLive()) {
268
+ this.playRangeStart_ = playRangeStart;
269
+ this.playRangeEnd_ = playRangeEnd;
270
+ }
271
+ }
272
+
273
+
254
274
  /**
255
275
  * Initialize and start streaming.
256
276
  *
@@ -1899,10 +1919,11 @@ shaka.media.StreamingEngine = class {
1899
1919
  // Rounding issues can cause us to remove the first frame of a Period, so
1900
1920
  // reduce the window start time slightly.
1901
1921
  const appendWindowStart = Math.max(0,
1902
- reference.appendWindowStart -
1922
+ Math.max(reference.appendWindowStart, this.playRangeStart_) -
1903
1923
  StreamingEngine.APPEND_WINDOW_START_FUDGE_);
1904
1924
  const appendWindowEnd =
1905
- reference.appendWindowEnd + StreamingEngine.APPEND_WINDOW_END_FUDGE_;
1925
+ Math.min(reference.appendWindowEnd, this.playRangeEnd_) +
1926
+ StreamingEngine.APPEND_WINDOW_END_FUDGE_;
1906
1927
 
1907
1928
  goog.asserts.assert(
1908
1929
  reference.startTime <= appendWindowEnd,
@@ -2670,7 +2691,10 @@ shaka.media.StreamingEngine = class {
2670
2691
  }
2671
2692
 
2672
2693
  // First fire an error event.
2673
- this.playerInterface_.onError(error);
2694
+ if (!error.handled ||
2695
+ error.code != shaka.util.Error.Code.SEGMENT_MISSING) {
2696
+ this.playerInterface_.onError(error);
2697
+ }
2674
2698
 
2675
2699
  // If the error was not handled by the application, call the failure
2676
2700
  // callback.
package/lib/player.js CHANGED
@@ -2401,6 +2401,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2401
2401
  this.config_.playRangeStart,
2402
2402
  this.config_.playRangeEnd);
2403
2403
 
2404
+ this.streamingEngine_.applyPlayRange(
2405
+ this.config_.playRangeStart, this.config_.playRangeEnd);
2404
2406
 
2405
2407
  const setupPlayhead = (startTime) => {
2406
2408
  this.playhead_ = this.createPlayhead(startTime);
@@ -7457,7 +7459,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
7457
7459
  * @export
7458
7460
  */
7459
7461
  // eslint-disable-next-line no-useless-concat
7460
- shaka.Player.version = 'v4.9.7' + '-uncompiled'; // x-release-please-version
7462
+ shaka.Player.version = 'v4.9.9' + '-uncompiled'; // x-release-please-version
7461
7463
 
7462
7464
  // Initialize the deprecation system using the version string we just set
7463
7465
  // on the player.
@@ -174,7 +174,12 @@ shaka.util.MimeUtils = class {
174
174
  return 'hevc'; // H265
175
175
  case base === 'dvh1':
176
176
  case base === 'dvhe':
177
- return 'dovi'; // Dolby Vision
177
+ return 'dovi-hevc'; // Dolby Vision based in HEVC
178
+ case base === 'dvav':
179
+ case base === 'dva1':
180
+ return 'dovi-avc'; // Dolby Vision based in AVC
181
+ case base === 'dav1':
182
+ return 'dovi-av1'; // Dolby Vision based in AV1
178
183
  }
179
184
  return base;
180
185
  }
@@ -275,11 +275,11 @@ shaka.util.Mp4BoxParsers = class {
275
275
  }
276
276
 
277
277
  /**
278
- * Parses a MP4A box.
278
+ * Parses an audio sample entry box.
279
279
  * @param {!shaka.util.DataViewReader} reader
280
- * @return {!shaka.util.ParsedMP4ABox}
280
+ * @return {!shaka.util.ParsedAudioSampleEntryBox}
281
281
  */
282
- static parseMP4A(reader) {
282
+ static audioSampleEntry(reader) {
283
283
  reader.skip(6); // Skip "reserved"
284
284
  reader.skip(2); // Skip "data_reference_index"
285
285
  reader.skip(8); // Skip "reserved"
@@ -604,6 +604,42 @@ shaka.util.Mp4BoxParsers = class {
604
604
  };
605
605
  }
606
606
 
607
+ /**
608
+ * Parses AV1 codec string with COLR box information.
609
+ *
610
+ * AV1 codec info: https://aomediacodec.github.io/av1-isobmff/#codecsparam
611
+ *
612
+ * @param {string} codec
613
+ * @param {!shaka.util.DataViewReader} reader
614
+ * @return {string}
615
+ */
616
+ static updateAV1CodecWithCOLRBox(codec, reader) {
617
+ const Mp4BoxParsers = shaka.util.Mp4BoxParsers;
618
+ const initialPosition = reader.getPosition();
619
+ const data = reader.readBytes(4);
620
+ let colorType = '';
621
+ colorType += String.fromCharCode(data[0]);
622
+ colorType += String.fromCharCode(data[1]);
623
+ colorType += String.fromCharCode(data[2]);
624
+ colorType += String.fromCharCode(data[3]);
625
+ if (colorType === 'nclx') {
626
+ const colorPrimaries = reader.readUint16();
627
+ const transferCharacteristics = reader.readUint16();
628
+ const matrixCoefficients = reader.readUint16();
629
+ const videoFullRangeFlag = reader.readUint8() >> 7;
630
+ const codecParts = codec.split('.');
631
+ if (codecParts.length == 10) {
632
+ codecParts[6] = Mp4BoxParsers.addLeadingZero_(colorPrimaries);
633
+ codecParts[7] = Mp4BoxParsers.addLeadingZero_(transferCharacteristics);
634
+ codecParts[8] = Mp4BoxParsers.addLeadingZero_(matrixCoefficients);
635
+ codecParts[9] = String(videoFullRangeFlag);
636
+ codec = codecParts.join('.');
637
+ }
638
+ }
639
+ reader.seek(initialPosition);
640
+ return codec;
641
+ }
642
+
607
643
  /**
608
644
  * Convert a number to hex
609
645
  * @param {number} x
@@ -820,7 +856,7 @@ shaka.util.ParsedTENCBox;
820
856
  *
821
857
  * @exportDoc
822
858
  */
823
- shaka.util.ParsedMP4ABox;
859
+ shaka.util.ParsedAudioSampleEntryBox;
824
860
 
825
861
  /**
826
862
  * @typedef {{
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.9.7",
4
+ "version": "4.9.9",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -2,6 +2,7 @@
2
2
  "AD_DURATION": "Duración del anuncio",
3
3
  "AD_PROGRESS": "Anuncio [AD_ON] de [NUM_ADS]",
4
4
  "AD_TIME": "Anuncio: [AD_TIME]",
5
+ "AIRPLAY": "AirPlay",
5
6
  "AUTO_QUALITY": "Automático",
6
7
  "BACK": "Atrás",
7
8
  "CAPTIONS": "Subtítulos",
@@ -26,6 +27,7 @@
26
27
  "PICTURE_IN_PICTURE": "Imagen en imagen",
27
28
  "PLAY": "Reproducir",
28
29
  "PLAYBACK_RATE": "Velocidad de reproducción",
30
+ "QUALITY": "Calidad",
29
31
  "RECENTER_VR": "Recentrar",
30
32
  "RESOLUTION": "Resolución",
31
33
  "REWIND": "Rebobinar",
@@ -1,7 +1,9 @@
1
1
  {
2
2
  "AD_DURATION": "Durée de l'annonce",
3
- "AD_PROGRESS": "Annonce [AD_ON] sur [NUM_ADS]",
4
- "AD_TIME": "Annonce : [AD_TIME]",
3
+ "AD_PROGRESS": "Annonce [AD_ON] sur [NUM_ADS]",
4
+ "AD_STATISTICS": "Statistiques de la annonce",
5
+ "AD_TIME": "Annonce : [AD_TIME]",
6
+ "AIRPLAY": "AirPlay",
5
7
  "AUTO_QUALITY": "Automatique",
6
8
  "BACK": "Retour",
7
9
  "CAPTIONS": "Sous-titres",
@@ -10,7 +12,7 @@
10
12
  "ENTER_PICTURE_IN_PICTURE": "Utiliser le mode Picture-in-Picture",
11
13
  "EXIT_FULL_SCREEN": "Quitter le mode plein écran",
12
14
  "EXIT_LOOP_MODE": "Arrêter la lecture en boucle de la vidéo en cours",
13
- "EXIT_PICTURE_IN_PICTURE": "Quitter le mode PIP (Picture-in-picture)",
15
+ "EXIT_PICTURE_IN_PICTURE": "Quitter le mode PIP (Picture-in-picture)",
14
16
  "FAST_FORWARD": "Avance rapide",
15
17
  "FULL_SCREEN": "Plein écran",
16
18
  "LANGUAGE": "Langue",
@@ -26,11 +28,18 @@
26
28
  "PICTURE_IN_PICTURE": "Picture-in-Picture",
27
29
  "PLAY": "Visionner",
28
30
  "PLAYBACK_RATE": "Vitesse de lecture",
31
+ "QUALITY": "Qualité",
32
+ "RECENTER_VR": "Recentrer",
33
+ "REPLAY": "Rejouer",
29
34
  "RESOLUTION": "Résolution",
30
35
  "REWIND": "Retour arrière",
31
36
  "SEEK": "Chercher",
32
37
  "SKIP_AD": "Passer l'annonce",
33
38
  "SKIP_TO_LIVE": "Accéder à la partie la plus récente du direct",
39
+ "STATISTICS": "Statistiques",
40
+ "SUBTITLE_FORCED": "Forcé",
41
+ "SURROUND": "Surround",
42
+ "TOGGLE_STEREOSCOPIC": "Stéréoscopique ON/OFF",
34
43
  "UNDETERMINED_LANGUAGE": "Langue indéterminée",
35
44
  "UNMUTE": "Réactiver le son",
36
45
  "UNRECOGNIZED_LANGUAGE": "Non reconnu",
@@ -1,7 +1,9 @@
1
1
  {
2
2
  "AD_DURATION": "Duração do anúncio",
3
3
  "AD_PROGRESS": "Anúncio [AD_ON] de [NUM_ADS]",
4
+ "AD_STATISTICS": "Estatísticas de anúncios",
4
5
  "AD_TIME": "Anúncio: [AD_TIME]",
6
+ "AIRPLAY": "AirPlay",
5
7
  "AUTO_QUALITY": "Automática",
6
8
  "BACK": "Voltar",
7
9
  "CAPTIONS": "Legendas",
@@ -26,11 +28,18 @@
26
28
  "PICTURE_IN_PICTURE": "Picture-in-picture",
27
29
  "PLAY": "Reproduzir",
28
30
  "PLAYBACK_RATE": "Velocidade da reprodução",
31
+ "QUALITY": "Qualidade",
32
+ "RECENTER_VR": "Recentralizar",
33
+ "REPLAY": "Replay",
29
34
  "RESOLUTION": "Resolução",
30
35
  "REWIND": "Retroceder",
31
36
  "SEEK": "Procurar",
32
37
  "SKIP_AD": "Pular anúncio",
33
38
  "SKIP_TO_LIVE": "Pular para transmissão ao vivo",
39
+ "STATISTICS": "Estatísticas",
40
+ "SUBTITLE_FORCED": "Forçado",
41
+ "SURROUND": "Surround",
42
+ "TOGGLE_STEREOSCOPIC": "Alternar estereoscópico",
34
43
  "UNDETERMINED_LANGUAGE": "Indeterminado",
35
44
  "UNMUTE": "Ativar som",
36
45
  "UNRECOGNIZED_LANGUAGE": "Não reconhecido",
@@ -1,7 +1,9 @@
1
1
  {
2
2
  "AD_DURATION": "Duração do anúncio",
3
3
  "AD_PROGRESS": "Anúncio [AD_ON] de [NUM_ADS]",
4
+ "AD_STATISTICS": "Estatísticas de anúncios",
4
5
  "AD_TIME": "Anúncio: [AD_TIME]",
6
+ "AIRPLAY": "AirPlay",
5
7
  "AUTO_QUALITY": "Automático",
6
8
  "BACK": "Anterior",
7
9
  "CAPTIONS": "Legendas",
@@ -26,11 +28,18 @@
26
28
  "PICTURE_IN_PICTURE": "Ecrã no ecrã",
27
29
  "PLAY": "Reproduzir",
28
30
  "PLAYBACK_RATE": "Velocidade de reprodução",
31
+ "QUALITY": "Qualidade",
32
+ "RECENTER_VR": "Recentrar",
33
+ "REPLAY": "Repetição",
29
34
  "RESOLUTION": "Resolução",
30
35
  "REWIND": "Rebobinar",
31
36
  "SEEK": "Procurar",
32
37
  "SKIP_AD": "Ignorar anúncio",
33
38
  "SKIP_TO_LIVE": "Avançar para o direto",
39
+ "STATISTICS": "Estatísticas",
40
+ "SUBTITLE_FORCED": "Forçado",
41
+ "SURROUND": "Envolvente",
42
+ "TOGGLE_STEREOSCOPIC": "Alternar estereoscópico",
34
43
  "UNDETERMINED_LANGUAGE": "Indeterminado",
35
44
  "UNMUTE": "Reativar o som",
36
45
  "UNRECOGNIZED_LANGUAGE": "Não reconhecido",