shaka-player 4.4.2 → 4.5.0
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/.github/workflows/release-please.yaml +2 -27
- package/CHANGELOG.md +67 -25
- package/README.md +16 -10
- package/demo/asset_card.js +18 -21
- package/demo/cast_receiver/index.html +0 -1
- package/demo/close_button.js +0 -3
- package/demo/common/asset.js +27 -5
- package/demo/common/assets.js +150 -52
- package/demo/config.js +192 -253
- package/demo/custom.js +39 -98
- package/demo/front.js +7 -10
- package/demo/index.html +19 -22
- package/demo/input.js +6 -11
- package/demo/input_container.js +8 -9
- package/demo/main.js +52 -124
- package/demo/search.js +23 -35
- package/demo/service_worker.js +0 -3
- package/demo/tooltip.js +3 -5
- package/demo/visualizer.js +3 -5
- package/demo/visualizer_button.js +1 -20
- package/dist/demo.compiled.debug.js +187 -211
- package/dist/demo.compiled.debug.map +4 -4
- package/dist/demo.compiled.js +187 -211
- package/dist/demo.compiled.map +4 -4
- package/dist/deps.js +27 -24
- package/dist/locales.js +31 -31
- package/dist/receiver.compiled.debug.js +42 -61
- package/dist/receiver.compiled.debug.map +4 -4
- package/dist/receiver.compiled.js +42 -61
- package/dist/receiver.compiled.map +4 -4
- package/dist/shaka-player.compiled.d.ts +728 -365
- package/dist/shaka-player.compiled.debug.d.ts +728 -365
- package/dist/shaka-player.compiled.debug.externs.js +475 -51
- package/dist/shaka-player.compiled.debug.js +576 -480
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +475 -51
- package/dist/shaka-player.compiled.js +1117 -1056
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +783 -410
- package/dist/shaka-player.ui.debug.d.ts +783 -410
- package/dist/shaka-player.ui.debug.externs.js +496 -51
- package/dist/shaka-player.ui.debug.js +647 -542
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +496 -51
- package/dist/shaka-player.ui.js +1260 -1194
- package/dist/shaka-player.ui.map +4 -4
- package/docs/design/lcevc-integration.md +14 -14
- package/docs/tutorials/faq.md +27 -55
- package/docs/tutorials/index.json +2 -1
- package/docs/tutorials/lcevc.md +118 -0
- package/docs/tutorials/offline.md +1 -1
- package/docs/tutorials/ui-customization.md +4 -0
- package/externs/css_style_declaration.js +19 -0
- package/externs/lcevc.js +37 -13
- package/externs/media_remote.js +68 -0
- package/externs/mediatailor.js +193 -0
- package/externs/pictureinpicture.js +11 -0
- package/externs/shaka/ads.js +27 -0
- package/externs/shaka/manifest.js +10 -5
- package/externs/shaka/manifest_parser.js +7 -1
- package/externs/shaka/offline.js +4 -0
- package/externs/shaka/player.js +12 -1
- package/karma.conf.js +7 -3
- package/lib/abr/simple_abr_manager.js +43 -3
- package/lib/ads/ad_manager.js +104 -50
- package/lib/ads/media_tailor_ad.js +297 -0
- package/lib/ads/media_tailor_ad_manager.js +828 -0
- package/lib/cea/ts_cea_parser.js +15 -2
- package/lib/config/codec_switching_strategy.js +24 -0
- package/lib/dash/content_protection.js +120 -2
- package/lib/dash/dash_parser.js +79 -13
- package/lib/dash/mpd_utils.js +10 -6
- package/lib/dash/segment_base.js +13 -5
- package/lib/dash/segment_list.js +13 -5
- package/lib/dash/segment_template.js +43 -85
- package/lib/dependencies/all.js +8 -7
- package/lib/hls/hls_parser.js +101 -37
- package/lib/lcevc/lcevc_dec.js +220 -0
- package/lib/media/adaptation_set.js +22 -11
- package/lib/media/adaptation_set_criteria.js +25 -7
- package/lib/media/media_source_engine.js +215 -27
- package/lib/media/segment_index.js +5 -5
- package/lib/media/segment_reference.js +10 -5
- package/lib/media/streaming_engine.js +44 -39
- package/lib/mss/mss_parser.js +1 -0
- package/lib/net/networking_engine.js +1 -0
- package/lib/offline/indexeddb/v1_storage_cell.js +1 -0
- package/lib/offline/indexeddb/v2_storage_cell.js +1 -0
- package/lib/offline/manifest_converter.js +1 -0
- package/lib/offline/storage.js +3 -0
- package/lib/player.js +142 -72
- package/lib/routing/payload.js +5 -1
- package/lib/text/cue.js +62 -47
- package/lib/text/ttml_text_parser.js +17 -0
- package/lib/text/ui_text_displayer.js +4 -0
- package/lib/text/vtt_text_parser.js +35 -22
- package/lib/transmuxer/h265.js +862 -0
- package/lib/transmuxer/mpeg_ts_transmuxer.js +3 -2
- package/lib/transmuxer/ts_transmuxer.js +160 -15
- package/lib/util/cmcd_manager.js +6 -1
- package/lib/util/error.js +28 -9
- package/lib/util/exp_golomb.js +30 -2
- package/lib/util/fake_event.js +3 -0
- package/lib/util/manifest_parser_utils.js +10 -4
- package/lib/util/mp4_generator.js +4 -4
- package/lib/util/periods.js +2 -0
- package/lib/util/platform.js +54 -0
- package/lib/util/player_configuration.js +8 -0
- package/lib/util/state_history.js +6 -2
- package/lib/util/stream_utils.js +133 -217
- package/lib/util/ts_parser.js +229 -43
- package/maintained-branches.md +3 -2
- package/package.json +4 -6
- package/roadmap.md +15 -5
- package/shaka-player.uncompiled.js +2 -1
- package/support.html +0 -1
- package/test/cast/cast_receiver_integration.js +47 -0
- package/test/codec_switching/codec_switching_integration.js +181 -0
- package/test/dash/dash_parser_content_protection_unit.js +2 -0
- package/test/dash/dash_parser_integration.js +73 -0
- package/test/dash/dash_parser_live_unit.js +2 -0
- package/test/dash/dash_parser_manifest_unit.js +47 -0
- package/test/dash/dash_parser_segment_base_unit.js +7 -0
- package/test/dash/dash_parser_segment_list_unit.js +23 -17
- package/test/dash/dash_parser_segment_template_unit.js +49 -0
- package/test/demo/demo_unit.js +0 -16
- package/test/hls/hls_live_unit.js +35 -0
- package/test/hls/hls_parser_unit.js +8 -61
- package/test/media/adaptation_set_criteria_unit.js +118 -0
- package/test/media/adaptation_set_unit.js +1 -0
- package/test/media/media_source_engine_unit.js +165 -1
- package/test/media/segment_index_unit.js +4 -4
- package/test/media/segment_prefetch_unit.js +1 -1
- package/test/media/streaming_engine_unit.js +17 -17
- package/test/mss/mss_parser_unit.js +2 -0
- package/test/offline/manifest_convert_unit.js +5 -0
- package/test/offline/storage_integration.js +1 -4
- package/test/player_unit.js +102 -131
- package/test/routing/walker_unit.js +1 -0
- package/test/test/assets/dash-aes-128/Fragments(video=0,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=20000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=40000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=60000000,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/Fragments(video=i,format=mpd-time-csf) +0 -0
- package/test/test/assets/dash-aes-128/dash.mpd +18 -0
- package/test/test/assets/dash-aes-128/license +1 -0
- package/test/test/assets/dash-multi-codec/audio_en_2c_128k_aac.mp4 +0 -0
- package/test/test/assets/dash-multi-codec/audio_es_2c_64k_opus.webm +0 -0
- package/test/test/assets/dash-multi-codec/dash.mpd +32 -0
- package/test/test/assets/dash-multi-codec/video_144p_108k_h264.mp4 +0 -0
- package/test/test/assets/hls-ts-h265/0.ts +0 -0
- package/test/test/assets/hls-ts-h265/hevc.m3u8 +6 -0
- package/test/test/assets/hls-ts-h265/index.m3u8 +7 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h265/media.m3u8 +9 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/media.m3u8 +24 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00000.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00001.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00002.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00003.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00004.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ac3-h264/s_00005.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0000.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0001.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0002.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/ChID_voices_1280x720p_25fps_h264_6ch_256kbps_ddp_sub_0003.ts +0 -0
- package/test/test/assets/hls-ts-muxed-ec3-h264/prog_index.m3u8 +14 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/index.m3u8 +23 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-1-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-2-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-3-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-4-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-5-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-6-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-7-v1-a1.ts +0 -0
- package/test/test/assets/hls-ts-muxed-mp3-h264/seg-8-v1-a1.ts +0 -0
- package/test/test/util/dash_parser_util.js +20 -7
- package/test/test/util/fake_ad_manager.js +20 -0
- package/test/test/util/fake_media_source_engine.js +8 -2
- package/test/test/util/manifest_generator.js +7 -3
- package/test/test/util/mss_parser_util.js +4 -0
- package/test/test/util/offline_utils.js +1 -0
- package/test/test/util/streaming_engine_util.js +7 -4
- package/test/text/ttml_text_parser_unit.js +52 -0
- package/test/text/vtt_text_parser_unit.js +105 -48
- package/test/transmuxer/transmuxer_integration.js +121 -4
- package/test/ui/ui_unit.js +3 -10
- package/test/util/stream_utils_unit.js +208 -74
- package/test/util/ts_parser_unit.js +1 -1
- package/ui/controls.js +125 -0
- package/ui/externs/ui.js +8 -1
- package/ui/pip_button.js +22 -120
- package/ui/remote_button.js +201 -0
- package/ui/ui.js +5 -2
- package/demo/common/message_ids.js +0 -309
- package/demo/locales/en.json +0 -287
- package/demo/locales/source.json +0 -1142
- package/externs/mux.js +0 -69
- package/lib/lcevc/lcevc_dil.js +0 -152
- package/lib/transmuxer/muxjs_transmuxer.js +0 -242
- package/test/transmuxer/muxjs_transmuxer_integration.js +0 -177
|
@@ -8,6 +8,7 @@ goog.provide('shaka.media.MediaSourceEngine');
|
|
|
8
8
|
|
|
9
9
|
goog.require('goog.asserts');
|
|
10
10
|
goog.require('shaka.log');
|
|
11
|
+
goog.require('shaka.config.CodecSwitchingStrategy');
|
|
11
12
|
goog.require('shaka.media.Capabilities');
|
|
12
13
|
goog.require('shaka.media.ContentWorkarounds');
|
|
13
14
|
goog.require('shaka.media.ClosedCaptionParser');
|
|
@@ -31,7 +32,7 @@ goog.require('shaka.util.Mp4Parser');
|
|
|
31
32
|
goog.require('shaka.util.Platform');
|
|
32
33
|
goog.require('shaka.util.PublicPromise');
|
|
33
34
|
goog.require('shaka.util.TsParser');
|
|
34
|
-
goog.require('shaka.lcevc.
|
|
35
|
+
goog.require('shaka.lcevc.Dec');
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
/**
|
|
@@ -53,10 +54,10 @@ shaka.media.MediaSourceEngine = class {
|
|
|
53
54
|
* MediaSourceEngine is destroyed, it will destroy the displayer.
|
|
54
55
|
* @param {!function(!Array.<shaka.extern.ID3Metadata>, number, ?number)=}
|
|
55
56
|
* onMetadata
|
|
56
|
-
* @param {?shaka.lcevc.
|
|
57
|
+
* @param {?shaka.lcevc.Dec} [lcevcDec] Optional - LCEVC Decoder Object
|
|
57
58
|
*
|
|
58
59
|
*/
|
|
59
|
-
constructor(video, textDisplayer, onMetadata,
|
|
60
|
+
constructor(video, textDisplayer, onMetadata, lcevcDec) {
|
|
60
61
|
/** @private {HTMLMediaElement} */
|
|
61
62
|
this.video_ = video;
|
|
62
63
|
|
|
@@ -91,8 +92,8 @@ shaka.media.MediaSourceEngine = class {
|
|
|
91
92
|
number, ?number)} */
|
|
92
93
|
this.onMetadata_ = onMetadata || onMetadataNoOp;
|
|
93
94
|
|
|
94
|
-
/** @private {?shaka.lcevc.
|
|
95
|
-
this.
|
|
95
|
+
/** @private {?shaka.lcevc.Dec} */
|
|
96
|
+
this.lcevcDec_ = lcevcDec || null;
|
|
96
97
|
|
|
97
98
|
/**
|
|
98
99
|
* @private {!Object.<string,
|
|
@@ -115,6 +116,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
115
116
|
/** @private {string} */
|
|
116
117
|
this.url_ = '';
|
|
117
118
|
|
|
119
|
+
/** @private {boolean} */
|
|
120
|
+
this.playbackHasBegun_ = false;
|
|
121
|
+
|
|
118
122
|
/** @private {MediaSource} */
|
|
119
123
|
this.mediaSource_ = this.createMediaSource(this.mediaSourceOpen_);
|
|
120
124
|
|
|
@@ -138,6 +142,9 @@ shaka.media.MediaSourceEngine = class {
|
|
|
138
142
|
|
|
139
143
|
/** @private {!shaka.util.PublicPromise.<number>} */
|
|
140
144
|
this.textSequenceModeOffset_ = new shaka.util.PublicPromise();
|
|
145
|
+
|
|
146
|
+
/** @private {boolean} */
|
|
147
|
+
this.needSplitMuxedContent_ = false;
|
|
141
148
|
}
|
|
142
149
|
|
|
143
150
|
/**
|
|
@@ -156,6 +163,11 @@ shaka.media.MediaSourceEngine = class {
|
|
|
156
163
|
this.eventManager_.listenOnce(
|
|
157
164
|
mediaSource, 'sourceopen', () => this.onSourceOpen_(p));
|
|
158
165
|
|
|
166
|
+
// Correctly set when playback has begun.
|
|
167
|
+
this.eventManager_.listenOnce(this.video_, 'playing', () => {
|
|
168
|
+
this.playbackHasBegun_ = true;
|
|
169
|
+
});
|
|
170
|
+
|
|
159
171
|
// Store the object URL for releasing it later.
|
|
160
172
|
this.url_ = shaka.media.MediaSourceEngine.createObjectURL(mediaSource);
|
|
161
173
|
|
|
@@ -341,7 +353,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
341
353
|
this.queues_ = {};
|
|
342
354
|
|
|
343
355
|
// This object is owned by Player
|
|
344
|
-
this.
|
|
356
|
+
this.lcevcDec_ = null;
|
|
345
357
|
}
|
|
346
358
|
|
|
347
359
|
/**
|
|
@@ -379,6 +391,8 @@ shaka.media.MediaSourceEngine = class {
|
|
|
379
391
|
async init(streamsByType, sequenceMode=false,
|
|
380
392
|
manifestType=shaka.media.ManifestParser.UNKNOWN,
|
|
381
393
|
ignoreManifestTimestampsInSegmentsMode=false) {
|
|
394
|
+
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
395
|
+
|
|
382
396
|
await this.mediaSourceOpen_;
|
|
383
397
|
|
|
384
398
|
this.sequenceMode_ = sequenceMode;
|
|
@@ -392,8 +406,13 @@ shaka.media.MediaSourceEngine = class {
|
|
|
392
406
|
|
|
393
407
|
for (const contentType of streamsByType.keys()) {
|
|
394
408
|
const stream = streamsByType.get(contentType);
|
|
395
|
-
this.initSourceBuffer_(contentType, stream);
|
|
396
|
-
this.
|
|
409
|
+
this.initSourceBuffer_(contentType, stream, stream.codecs);
|
|
410
|
+
if (this.needSplitMuxedContent_) {
|
|
411
|
+
this.queues_[ContentType.AUDIO] = [];
|
|
412
|
+
this.queues_[ContentType.VIDEO] = [];
|
|
413
|
+
} else {
|
|
414
|
+
this.queues_[contentType] = [];
|
|
415
|
+
}
|
|
397
416
|
}
|
|
398
417
|
}
|
|
399
418
|
|
|
@@ -402,9 +421,10 @@ shaka.media.MediaSourceEngine = class {
|
|
|
402
421
|
*
|
|
403
422
|
* @param {shaka.util.ManifestParserUtils.ContentType} contentType
|
|
404
423
|
* @param {shaka.extern.Stream} stream
|
|
424
|
+
* @param {string} codecs
|
|
405
425
|
* @private
|
|
406
426
|
*/
|
|
407
|
-
initSourceBuffer_(contentType, stream) {
|
|
427
|
+
initSourceBuffer_(contentType, stream, codecs) {
|
|
408
428
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
409
429
|
|
|
410
430
|
goog.asserts.assert(
|
|
@@ -412,7 +432,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
412
432
|
'Type negotiation should happen before MediaSourceEngine.init!');
|
|
413
433
|
|
|
414
434
|
let mimeType = shaka.util.MimeUtils.getFullType(
|
|
415
|
-
stream.mimeType,
|
|
435
|
+
stream.mimeType, codecs);
|
|
416
436
|
if (contentType == ContentType.TEXT) {
|
|
417
437
|
this.reinitText(mimeType, this.sequenceMode_, stream.external);
|
|
418
438
|
} else {
|
|
@@ -424,9 +444,19 @@ shaka.media.MediaSourceEngine = class {
|
|
|
424
444
|
}
|
|
425
445
|
const mimeTypeWithAllCodecs =
|
|
426
446
|
shaka.util.MimeUtils.getFullTypeWithAllCodecs(
|
|
427
|
-
stream.mimeType,
|
|
447
|
+
stream.mimeType, codecs);
|
|
428
448
|
const TransmuxerEngine = shaka.transmuxer.TransmuxerEngine;
|
|
429
449
|
if (needTransmux) {
|
|
450
|
+
const audioCodec = shaka.util.ManifestParserUtils.guessCodecsSafe(
|
|
451
|
+
ContentType.AUDIO, (codecs || '').split(','));
|
|
452
|
+
const videoCodec = shaka.util.ManifestParserUtils.guessCodecsSafe(
|
|
453
|
+
ContentType.VIDEO, (codecs || '').split(','));
|
|
454
|
+
if (audioCodec && videoCodec) {
|
|
455
|
+
this.needSplitMuxedContent_ = true;
|
|
456
|
+
this.initSourceBuffer_(ContentType.AUDIO, stream, audioCodec);
|
|
457
|
+
this.initSourceBuffer_(ContentType.VIDEO, stream, videoCodec);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
430
460
|
const transmuxerPlugin =
|
|
431
461
|
TransmuxerEngine.findTransmuxer(mimeTypeWithAllCodecs);
|
|
432
462
|
if (transmuxerPlugin) {
|
|
@@ -513,7 +543,8 @@ shaka.media.MediaSourceEngine = class {
|
|
|
513
543
|
* @return {?number} The timestamp in seconds, or null if nothing is buffered.
|
|
514
544
|
*/
|
|
515
545
|
bufferStart(contentType) {
|
|
516
|
-
if (this.reloadingMediaSource_
|
|
546
|
+
if (this.reloadingMediaSource_ ||
|
|
547
|
+
!Object.keys(this.sourceBuffers_).length) {
|
|
517
548
|
return null;
|
|
518
549
|
}
|
|
519
550
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
@@ -743,7 +774,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
743
774
|
*/
|
|
744
775
|
async appendBuffer(
|
|
745
776
|
contentType, data, reference, stream, hasClosedCaptions, seeked = false,
|
|
746
|
-
adaptation = false, isChunkedData = false) {
|
|
777
|
+
adaptation = false, isChunkedData = false, fromSplit = false) {
|
|
747
778
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
748
779
|
|
|
749
780
|
if (contentType == ContentType.TEXT) {
|
|
@@ -759,6 +790,21 @@ shaka.media.MediaSourceEngine = class {
|
|
|
759
790
|
return;
|
|
760
791
|
}
|
|
761
792
|
|
|
793
|
+
if (!fromSplit && this.needSplitMuxedContent_) {
|
|
794
|
+
await this.appendBuffer(ContentType.AUDIO, data, reference, stream,
|
|
795
|
+
hasClosedCaptions, seeked, adaptation, isChunkedData,
|
|
796
|
+
/* fromSplit= */ true);
|
|
797
|
+
await this.appendBuffer(ContentType.VIDEO, data, reference, stream,
|
|
798
|
+
hasClosedCaptions, seeked, adaptation, isChunkedData,
|
|
799
|
+
/* fromSplit= */ true);
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
if (!this.sourceBuffers_[contentType]) {
|
|
804
|
+
shaka.log.warning('Attempted to restore a non-existent source buffer');
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
|
|
762
808
|
let timestampOffset = this.sourceBuffers_[contentType].timestampOffset;
|
|
763
809
|
|
|
764
810
|
let mimeType = this.sourceBufferTypes_[contentType];
|
|
@@ -850,7 +896,7 @@ shaka.media.MediaSourceEngine = class {
|
|
|
850
896
|
if (goog.DEBUG && reference && !reference.isPreload() && !isChunkedData) {
|
|
851
897
|
bufferedBefore = this.getBuffered_(contentType);
|
|
852
898
|
}
|
|
853
|
-
this.append_(contentType, data);
|
|
899
|
+
this.append_(contentType, data, timestampOffset);
|
|
854
900
|
});
|
|
855
901
|
|
|
856
902
|
if (goog.DEBUG && reference && !reference.isPreload() && !isChunkedData) {
|
|
@@ -910,6 +956,11 @@ shaka.media.MediaSourceEngine = class {
|
|
|
910
956
|
await this.enqueueOperation_(
|
|
911
957
|
contentType,
|
|
912
958
|
() => this.remove_(contentType, startTime, endTime));
|
|
959
|
+
if (this.needSplitMuxedContent_) {
|
|
960
|
+
await this.enqueueOperation_(
|
|
961
|
+
ContentType.AUDIO,
|
|
962
|
+
() => this.remove_(ContentType.AUDIO, startTime, endTime));
|
|
963
|
+
}
|
|
913
964
|
}
|
|
914
965
|
}
|
|
915
966
|
|
|
@@ -931,6 +982,12 @@ shaka.media.MediaSourceEngine = class {
|
|
|
931
982
|
await this.enqueueOperation_(
|
|
932
983
|
contentType,
|
|
933
984
|
() => this.remove_(contentType, 0, this.mediaSource_.duration));
|
|
985
|
+
if (this.needSplitMuxedContent_) {
|
|
986
|
+
await this.enqueueOperation_(
|
|
987
|
+
ContentType.AUDIO,
|
|
988
|
+
() => this.remove_(
|
|
989
|
+
ContentType.AUDIO, 0, this.mediaSource_.duration));
|
|
990
|
+
}
|
|
934
991
|
}
|
|
935
992
|
}
|
|
936
993
|
|
|
@@ -961,6 +1018,11 @@ shaka.media.MediaSourceEngine = class {
|
|
|
961
1018
|
await this.enqueueOperation_(
|
|
962
1019
|
contentType,
|
|
963
1020
|
() => this.flush_(contentType));
|
|
1021
|
+
if (this.needSplitMuxedContent_) {
|
|
1022
|
+
await this.enqueueOperation_(
|
|
1023
|
+
ContentType.AUDIO,
|
|
1024
|
+
() => this.flush_(ContentType.AUDIO));
|
|
1025
|
+
}
|
|
964
1026
|
}
|
|
965
1027
|
|
|
966
1028
|
/**
|
|
@@ -1014,16 +1076,33 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1014
1076
|
operations.push(this.enqueueOperation_(
|
|
1015
1077
|
contentType,
|
|
1016
1078
|
() => this.abort_(contentType)));
|
|
1079
|
+
if (this.needSplitMuxedContent_) {
|
|
1080
|
+
operations.push(this.enqueueOperation_(
|
|
1081
|
+
ContentType.AUDIO,
|
|
1082
|
+
() => this.abort_(ContentType.AUDIO)));
|
|
1083
|
+
}
|
|
1017
1084
|
}
|
|
1018
1085
|
if (!ignoreTimestampOffset) {
|
|
1019
1086
|
operations.push(this.enqueueOperation_(
|
|
1020
1087
|
contentType,
|
|
1021
1088
|
() => this.setTimestampOffset_(contentType, timestampOffset)));
|
|
1089
|
+
if (this.needSplitMuxedContent_) {
|
|
1090
|
+
operations.push(this.enqueueOperation_(
|
|
1091
|
+
ContentType.AUDIO,
|
|
1092
|
+
() => this.setTimestampOffset_(
|
|
1093
|
+
ContentType.AUDIO, timestampOffset)));
|
|
1094
|
+
}
|
|
1022
1095
|
}
|
|
1023
1096
|
operations.push(this.enqueueOperation_(
|
|
1024
1097
|
contentType,
|
|
1025
1098
|
() => this.setAppendWindow_(
|
|
1026
1099
|
contentType, appendWindowStart, appendWindowEnd)));
|
|
1100
|
+
if (this.needSplitMuxedContent_) {
|
|
1101
|
+
operations.push(this.enqueueOperation_(
|
|
1102
|
+
ContentType.AUDIO,
|
|
1103
|
+
() => this.setAppendWindow_(
|
|
1104
|
+
ContentType.AUDIO, appendWindowStart, appendWindowEnd)));
|
|
1105
|
+
}
|
|
1027
1106
|
|
|
1028
1107
|
await Promise.all(operations);
|
|
1029
1108
|
}
|
|
@@ -1054,9 +1133,19 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1054
1133
|
this.enqueueOperation_(
|
|
1055
1134
|
contentType,
|
|
1056
1135
|
() => this.abort_(contentType));
|
|
1136
|
+
if (this.needSplitMuxedContent_) {
|
|
1137
|
+
this.enqueueOperation_(
|
|
1138
|
+
ContentType.AUDIO,
|
|
1139
|
+
() => this.abort_(ContentType.AUDIO));
|
|
1140
|
+
}
|
|
1057
1141
|
await this.enqueueOperation_(
|
|
1058
1142
|
contentType,
|
|
1059
1143
|
() => this.setTimestampOffset_(contentType, timestampOffset));
|
|
1144
|
+
if (this.needSplitMuxedContent_) {
|
|
1145
|
+
await this.enqueueOperation_(
|
|
1146
|
+
ContentType.AUDIO,
|
|
1147
|
+
() => this.setTimestampOffset_(ContentType.AUDIO, timestampOffset));
|
|
1148
|
+
}
|
|
1060
1149
|
}
|
|
1061
1150
|
|
|
1062
1151
|
/**
|
|
@@ -1120,16 +1209,17 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1120
1209
|
* Append data to the SourceBuffer.
|
|
1121
1210
|
* @param {shaka.util.ManifestParserUtils.ContentType} contentType
|
|
1122
1211
|
* @param {BufferSource} data
|
|
1212
|
+
* @param {number} timestampOffset
|
|
1123
1213
|
* @private
|
|
1124
1214
|
*/
|
|
1125
|
-
append_(contentType, data) {
|
|
1215
|
+
append_(contentType, data, timestampOffset) {
|
|
1126
1216
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
1127
1217
|
|
|
1128
|
-
// Append only video data to the LCEVC
|
|
1129
|
-
if (contentType == ContentType.VIDEO && this.
|
|
1130
|
-
// Append video buffers to the LCEVC
|
|
1218
|
+
// Append only video data to the LCEVC Dec.
|
|
1219
|
+
if (contentType == ContentType.VIDEO && this.lcevcDec_) {
|
|
1220
|
+
// Append video buffers to the LCEVC Dec for parsing and storing
|
|
1131
1221
|
// of LCEVC data.
|
|
1132
|
-
this.
|
|
1222
|
+
this.lcevcDec_.appendBuffer(data, timestampOffset);
|
|
1133
1223
|
}
|
|
1134
1224
|
|
|
1135
1225
|
// This will trigger an 'updateend' event.
|
|
@@ -1292,7 +1382,6 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1292
1382
|
*/
|
|
1293
1383
|
enqueueOperation_(contentType, start) {
|
|
1294
1384
|
this.destroyer_.ensureNotDestroyed();
|
|
1295
|
-
|
|
1296
1385
|
const operation = {
|
|
1297
1386
|
start: start,
|
|
1298
1387
|
p: new shaka.util.PublicPromise(),
|
|
@@ -1563,8 +1652,24 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1563
1652
|
*/
|
|
1564
1653
|
async reset_(streamsByType) {
|
|
1565
1654
|
const Functional = shaka.util.Functional;
|
|
1655
|
+
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
1566
1656
|
this.reloadingMediaSource_ = true;
|
|
1657
|
+
this.needSplitMuxedContent_ = false;
|
|
1567
1658
|
const currentTime = this.video_.currentTime;
|
|
1659
|
+
|
|
1660
|
+
// When codec switching if the user is currently paused we don't want
|
|
1661
|
+
// to trigger a play when switching codec.
|
|
1662
|
+
// Playing can also end up in a paused state after a codec switch
|
|
1663
|
+
// so we need to remember the current states.
|
|
1664
|
+
const previousAutoPlayState = this.video_.autoplay;
|
|
1665
|
+
const previousPausedState = this.video_.paused;
|
|
1666
|
+
if (this.playbackHasBegun_) {
|
|
1667
|
+
// Only set autoplay to false if the video playback has already begun.
|
|
1668
|
+
// When a codec switch happens before playback has begun this can cause
|
|
1669
|
+
// autoplay not to work as expected.
|
|
1670
|
+
this.video_.autoplay = false;
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1568
1673
|
try {
|
|
1569
1674
|
this.eventManager_.removeAll();
|
|
1570
1675
|
|
|
@@ -1598,7 +1703,6 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1598
1703
|
}
|
|
1599
1704
|
await Promise.all(cleanup);
|
|
1600
1705
|
this.transmuxers_ = {};
|
|
1601
|
-
this.queues_ = {};
|
|
1602
1706
|
this.sourceBuffers_ = {};
|
|
1603
1707
|
|
|
1604
1708
|
const previousDuration = this.mediaSource_.duration;
|
|
@@ -1622,7 +1726,13 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1622
1726
|
|
|
1623
1727
|
for (const contentType of streamsByType.keys()) {
|
|
1624
1728
|
const stream = streamsByType.get(contentType);
|
|
1625
|
-
this.initSourceBuffer_(contentType, stream);
|
|
1729
|
+
this.initSourceBuffer_(contentType, stream, stream.codecs);
|
|
1730
|
+
if (this.needSplitMuxedContent_) {
|
|
1731
|
+
this.queues_[ContentType.AUDIO] = [];
|
|
1732
|
+
this.queues_[ContentType.VIDEO] = [];
|
|
1733
|
+
} else {
|
|
1734
|
+
this.queues_[contentType] = [];
|
|
1735
|
+
}
|
|
1626
1736
|
}
|
|
1627
1737
|
|
|
1628
1738
|
// Fake a seek to catchup the playhead.
|
|
@@ -1631,6 +1741,17 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1631
1741
|
await sourceBufferAdded;
|
|
1632
1742
|
} finally {
|
|
1633
1743
|
this.reloadingMediaSource_ = false;
|
|
1744
|
+
|
|
1745
|
+
this.destroyer_.ensureNotDestroyed();
|
|
1746
|
+
|
|
1747
|
+
this.eventManager_.listenOnce(this.video_, 'canplay', () => {
|
|
1748
|
+
this.destroyer_.ensureNotDestroyed();
|
|
1749
|
+
|
|
1750
|
+
this.video_.autoplay = previousAutoPlayState;
|
|
1751
|
+
if (!previousPausedState) {
|
|
1752
|
+
this.video_.play();
|
|
1753
|
+
}
|
|
1754
|
+
});
|
|
1634
1755
|
}
|
|
1635
1756
|
}
|
|
1636
1757
|
|
|
@@ -1696,7 +1817,10 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1696
1817
|
return false;
|
|
1697
1818
|
}
|
|
1698
1819
|
|
|
1699
|
-
if (
|
|
1820
|
+
if (this.config_.codecSwitchingStrategy ===
|
|
1821
|
+
shaka.config.CodecSwitchingStrategy.SMOOTH &&
|
|
1822
|
+
shaka.media.Capabilities.isChangeTypeSupported() &&
|
|
1823
|
+
!this.needSplitMuxedContent_) {
|
|
1700
1824
|
await this.changeType(contentType, newMimeType, transmuxer);
|
|
1701
1825
|
} else {
|
|
1702
1826
|
if (transmuxer) {
|
|
@@ -1708,11 +1832,75 @@ shaka.media.MediaSourceEngine = class {
|
|
|
1708
1832
|
}
|
|
1709
1833
|
|
|
1710
1834
|
/**
|
|
1711
|
-
*
|
|
1712
|
-
*
|
|
1835
|
+
* Returns true if it's necessary codec switch to load the new stream.
|
|
1836
|
+
*
|
|
1837
|
+
* @param {shaka.util.ManifestParserUtils.ContentType} contentType
|
|
1838
|
+
* @param {shaka.extern.Stream} stream
|
|
1839
|
+
* @return {boolean}
|
|
1840
|
+
* @private
|
|
1841
|
+
*/
|
|
1842
|
+
isCodecSwitchNecessary_(contentType, stream) {
|
|
1843
|
+
const MimeUtils = shaka.util.MimeUtils;
|
|
1844
|
+
const currentCodec = MimeUtils.getCodecBase(
|
|
1845
|
+
MimeUtils.getCodecs(this.sourceBufferTypes_[contentType]));
|
|
1846
|
+
const currentBasicType = MimeUtils.getBasicType(
|
|
1847
|
+
this.sourceBufferTypes_[contentType]);
|
|
1848
|
+
|
|
1849
|
+
let newMimeType = shaka.util.MimeUtils.getFullType(
|
|
1850
|
+
stream.mimeType, stream.codecs);
|
|
1851
|
+
let needTransmux = this.config_.forceTransmux;
|
|
1852
|
+
if (!shaka.media.Capabilities.isTypeSupported(newMimeType) ||
|
|
1853
|
+
(!this.sequenceMode_ &&
|
|
1854
|
+
shaka.util.MimeUtils.RAW_FORMATS.includes(newMimeType))) {
|
|
1855
|
+
needTransmux = true;
|
|
1856
|
+
}
|
|
1857
|
+
const newMimeTypeWithAllCodecs =
|
|
1858
|
+
shaka.util.MimeUtils.getFullTypeWithAllCodecs(
|
|
1859
|
+
stream.mimeType, stream.codecs);
|
|
1860
|
+
const TransmuxerEngine = shaka.transmuxer.TransmuxerEngine;
|
|
1861
|
+
if (needTransmux) {
|
|
1862
|
+
const transmuxerPlugin =
|
|
1863
|
+
TransmuxerEngine.findTransmuxer(newMimeTypeWithAllCodecs);
|
|
1864
|
+
if (transmuxerPlugin) {
|
|
1865
|
+
const transmuxer = transmuxerPlugin();
|
|
1866
|
+
newMimeType =
|
|
1867
|
+
transmuxer.convertCodecs(contentType, newMimeTypeWithAllCodecs);
|
|
1868
|
+
transmuxer.destroy();
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
const newCodec = MimeUtils.getCodecBase(
|
|
1873
|
+
MimeUtils.getCodecs(newMimeType));
|
|
1874
|
+
const newBasicType = MimeUtils.getBasicType(newMimeType);
|
|
1875
|
+
|
|
1876
|
+
return currentCodec !== newCodec || currentBasicType !== newBasicType;
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
/**
|
|
1880
|
+
* Returns true if it's necessary reset the media source to load the
|
|
1881
|
+
* new stream.
|
|
1882
|
+
*
|
|
1883
|
+
* @param {shaka.util.ManifestParserUtils.ContentType} contentType
|
|
1884
|
+
* @param {shaka.extern.Stream} stream
|
|
1885
|
+
* @return {boolean}
|
|
1886
|
+
*/
|
|
1887
|
+
isResetMediaSourceNecessary(contentType, stream) {
|
|
1888
|
+
if (!this.isCodecSwitchNecessary_(contentType, stream)) {
|
|
1889
|
+
return false;
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
return this.config_.codecSwitchingStrategy !==
|
|
1893
|
+
shaka.config.CodecSwitchingStrategy.SMOOTH ||
|
|
1894
|
+
!shaka.media.Capabilities.isChangeTypeSupported() ||
|
|
1895
|
+
this.needSplitMuxedContent_;
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
/**
|
|
1899
|
+
* Update LCEVC Decoder object when ready for LCEVC Decode.
|
|
1900
|
+
* @param {?shaka.lcevc.Dec} lcevcDec
|
|
1713
1901
|
*/
|
|
1714
|
-
|
|
1715
|
-
this.
|
|
1902
|
+
updateLcevcDec(lcevcDec) {
|
|
1903
|
+
this.lcevcDec_ = lcevcDec;
|
|
1716
1904
|
}
|
|
1717
1905
|
};
|
|
1718
1906
|
|
|
@@ -379,7 +379,7 @@ shaka.media.SegmentIndex = class {
|
|
|
379
379
|
lastReference.tileDuration,
|
|
380
380
|
lastReference.syncTime,
|
|
381
381
|
lastReference.status,
|
|
382
|
-
lastReference.
|
|
382
|
+
lastReference.aes128Key,
|
|
383
383
|
);
|
|
384
384
|
this.references[this.references.length - 1].discontinuitySequence =
|
|
385
385
|
lastReference.discontinuitySequence;
|
|
@@ -708,7 +708,7 @@ shaka.media.MetaSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
708
708
|
}
|
|
709
709
|
|
|
710
710
|
numPassedInEarlierIndexes += index.numEvicted_ +
|
|
711
|
-
index.
|
|
711
|
+
index.getNumReferences();
|
|
712
712
|
}
|
|
713
713
|
|
|
714
714
|
return null;
|
|
@@ -732,9 +732,9 @@ shaka.media.MetaSegmentIndex = class extends shaka.media.SegmentIndex {
|
|
|
732
732
|
return reference;
|
|
733
733
|
}
|
|
734
734
|
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
sawSegments = sawSegments ||
|
|
735
|
+
const num = index.getNumReferences();
|
|
736
|
+
numPassedInEarlierIndexes += index.numEvicted_ + num;
|
|
737
|
+
sawSegments = sawSegments || num != 0;
|
|
738
738
|
}
|
|
739
739
|
|
|
740
740
|
return null;
|
|
@@ -32,9 +32,11 @@ shaka.media.InitSegmentReference = class {
|
|
|
32
32
|
* the quality of the media associated with this init segment.
|
|
33
33
|
* @param {(null|number)=} timescale
|
|
34
34
|
* @param {(null|BufferSource)=} segmentData
|
|
35
|
+
* @param {?shaka.extern.aes128Key=} aes128Key
|
|
36
|
+
* The segment's AES-128-CBC full segment encryption key and iv.
|
|
35
37
|
*/
|
|
36
38
|
constructor(uris, startByte, endByte, mediaQuality = null, timescale = null,
|
|
37
|
-
segmentData = null) {
|
|
39
|
+
segmentData = null, aes128Key = null) {
|
|
38
40
|
/** @type {function():!Array.<string>} */
|
|
39
41
|
this.getUris = uris;
|
|
40
42
|
|
|
@@ -52,6 +54,9 @@ shaka.media.InitSegmentReference = class {
|
|
|
52
54
|
|
|
53
55
|
/** @type {BufferSource|null} */
|
|
54
56
|
this.segmentData = segmentData;
|
|
57
|
+
|
|
58
|
+
/** @type {?shaka.extern.aes128Key} */
|
|
59
|
+
this.aes128Key = aes128Key;
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
/**
|
|
@@ -191,7 +196,7 @@ shaka.media.SegmentReference = class {
|
|
|
191
196
|
* @param {shaka.media.SegmentReference.Status=} status
|
|
192
197
|
* The segment status is used to indicate that a segment does not exist or is
|
|
193
198
|
* not available.
|
|
194
|
-
* @param {?shaka.extern.
|
|
199
|
+
* @param {?shaka.extern.aes128Key=} aes128Key
|
|
195
200
|
* The segment's AES-128-CBC full segment encryption key and iv.
|
|
196
201
|
*/
|
|
197
202
|
constructor(
|
|
@@ -199,7 +204,7 @@ shaka.media.SegmentReference = class {
|
|
|
199
204
|
timestampOffset, appendWindowStart, appendWindowEnd,
|
|
200
205
|
partialReferences = [], tilesLayout = '', tileDuration = null,
|
|
201
206
|
syncTime = null, status = shaka.media.SegmentReference.Status.AVAILABLE,
|
|
202
|
-
|
|
207
|
+
aes128Key = null) {
|
|
203
208
|
// A preload hinted Partial Segment has the same startTime and endTime.
|
|
204
209
|
goog.asserts.assert(startTime <= endTime,
|
|
205
210
|
'startTime must be less than or equal to endTime');
|
|
@@ -271,8 +276,8 @@ shaka.media.SegmentReference = class {
|
|
|
271
276
|
/** @type {boolean} */
|
|
272
277
|
this.byterangeOptimization = false;
|
|
273
278
|
|
|
274
|
-
/** @type {?shaka.extern.
|
|
275
|
-
this.
|
|
279
|
+
/** @type {?shaka.extern.aes128Key} */
|
|
280
|
+
this.aes128Key = aes128Key;
|
|
276
281
|
|
|
277
282
|
/** @type {?shaka.media.SegmentReference.ThumbnailSprite} */
|
|
278
283
|
this.thumbnailSprite = null;
|