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
package/externs/mux.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/*! @license
|
|
2
|
-
* Shaka Player
|
|
3
|
-
* Copyright 2016 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @fileoverview Externs for mux.js library.
|
|
9
|
-
* @externs
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @typedef {{
|
|
15
|
-
* mp4: typeof muxjs.mp4
|
|
16
|
-
* }}
|
|
17
|
-
* @const
|
|
18
|
-
*/
|
|
19
|
-
var muxjs = {};
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
/** @const */
|
|
23
|
-
muxjs.mp4 = {};
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
muxjs.mp4.Transmuxer = class {
|
|
27
|
-
/** @param {Object=} options */
|
|
28
|
-
constructor(options) {}
|
|
29
|
-
|
|
30
|
-
/** @param {number} time */
|
|
31
|
-
setBaseMediaDecodeTime(time) {}
|
|
32
|
-
|
|
33
|
-
/** @param {!Uint8Array} data */
|
|
34
|
-
push(data) {}
|
|
35
|
-
|
|
36
|
-
flush() {}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Add a handler for a specified event type.
|
|
40
|
-
* @param {string} type Event name
|
|
41
|
-
* @param {Function} listener The callback to be invoked
|
|
42
|
-
*/
|
|
43
|
-
on(type, listener) {}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Remove a handler for a specified event type.
|
|
47
|
-
* @param {string} type Event name
|
|
48
|
-
* @param {Function} listener The callback to be removed
|
|
49
|
-
*/
|
|
50
|
-
off(type, listener) {}
|
|
51
|
-
|
|
52
|
-
/** Remove all handlers and clean up. */
|
|
53
|
-
dispose() {}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* @typedef {{
|
|
59
|
-
* initSegment: !Uint8Array,
|
|
60
|
-
* data: !Uint8Array
|
|
61
|
-
* }}
|
|
62
|
-
*
|
|
63
|
-
* @description Transmuxed data from mux.js.
|
|
64
|
-
* @property {!Uint8Array} initSegment
|
|
65
|
-
* @property {!Uint8Array} data
|
|
66
|
-
* @exportDoc
|
|
67
|
-
*/
|
|
68
|
-
muxjs.mp4.Transmuxer.Segment;
|
|
69
|
-
|
package/lib/lcevc/lcevc_dil.js
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
/*! @license
|
|
2
|
-
* Shaka Player
|
|
3
|
-
* Copyright 2016 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
goog.provide('shaka.lcevc.Dil');
|
|
8
|
-
goog.require('shaka.log');
|
|
9
|
-
goog.require('shaka.util.IReleasable');
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @summary
|
|
13
|
-
* lcevcDil - (MPEG-5 Part 2 LCEVC - Decoder Integration Layer) provides
|
|
14
|
-
* all the operations related to the enhancement and rendering
|
|
15
|
-
* of LCEVC enabled streams and on to a canvas.
|
|
16
|
-
* @implements {shaka.util.IReleasable}
|
|
17
|
-
* @export
|
|
18
|
-
*/
|
|
19
|
-
shaka.lcevc.Dil = class {
|
|
20
|
-
/**
|
|
21
|
-
* @param {HTMLVideoElement} media The video element that will be attached to
|
|
22
|
-
* LCEVC Dil for input.
|
|
23
|
-
* @param {HTMLCanvasElement} canvas The canvas element that will be attached
|
|
24
|
-
* to LCEVC Dil to render the enhanced frames.
|
|
25
|
-
* @param {shaka.extern.LcevcConfiguration} dilConfig The LCEVC DIL
|
|
26
|
-
* config object to initialize the LCEVC DIL.
|
|
27
|
-
*/
|
|
28
|
-
constructor(media, canvas, dilConfig) {
|
|
29
|
-
/** @private {?LcevcDil.LcevcDIL} */
|
|
30
|
-
this.dil_ = null;
|
|
31
|
-
|
|
32
|
-
/** @private {number} */
|
|
33
|
-
this.variantId_ = -1;
|
|
34
|
-
|
|
35
|
-
/** @private {HTMLVideoElement} */
|
|
36
|
-
this.media_ = media;
|
|
37
|
-
|
|
38
|
-
/** @private {HTMLCanvasElement} */
|
|
39
|
-
this.canvas_ = canvas;
|
|
40
|
-
|
|
41
|
-
/** @private {shaka.extern.LcevcConfiguration} */
|
|
42
|
-
this.dilConfig_ = dilConfig;
|
|
43
|
-
|
|
44
|
-
this.create_();
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Append data to the LCEVC Dil.
|
|
49
|
-
* @param {BufferSource} data
|
|
50
|
-
*/
|
|
51
|
-
appendBuffer(data) {
|
|
52
|
-
if (this.dil_) {
|
|
53
|
-
this.dil_.appendBuffer(data, 'video', this.variantId_);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Hide the canvas specifically in the case of a DRM Content
|
|
59
|
-
*/
|
|
60
|
-
hideCanvas() {
|
|
61
|
-
if (this.dil_) {
|
|
62
|
-
this.canvas_.classList.add('shaka-hidden');
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Create LCEVC Dil.
|
|
68
|
-
* @private
|
|
69
|
-
*/
|
|
70
|
-
create_() {
|
|
71
|
-
if (this.isSupported_() && !this.dil_) {
|
|
72
|
-
if (LcevcDil.SupportObject.webGLSupport(this.canvas_)) {
|
|
73
|
-
// Make sure the canvas is not hidden from a previous playback session.
|
|
74
|
-
this.canvas_.classList.remove('shaka-hidden');
|
|
75
|
-
this.dil_ = new LcevcDil.LcevcDil(
|
|
76
|
-
this.media_,
|
|
77
|
-
this.canvas_,
|
|
78
|
-
this.dilConfig_);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Close LCEVC Dil.
|
|
85
|
-
* @override
|
|
86
|
-
* @export
|
|
87
|
-
*/
|
|
88
|
-
release() {
|
|
89
|
-
if (this.dil_) {
|
|
90
|
-
this.dil_.close();
|
|
91
|
-
this.dil_ = null;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Check if the LCEVC Dil lib is present and is supported by the browser.
|
|
97
|
-
* @return {boolean}
|
|
98
|
-
* @private
|
|
99
|
-
*/
|
|
100
|
-
isSupported_() {
|
|
101
|
-
if (typeof libDPIModule === 'undefined') {
|
|
102
|
-
shaka.log.alwaysWarn(
|
|
103
|
-
'Could not Find LCEVC Library dependencies on this page');
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (typeof LcevcDil === 'undefined') {
|
|
107
|
-
shaka.log.alwaysWarn('Could not Find LCEVC Library on this page');
|
|
108
|
-
} else {
|
|
109
|
-
if (!LcevcDil.SupportObject.SupportStatus) {
|
|
110
|
-
shaka.log.alwaysWarn(LcevcDil.SupportObject.SupportError);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return typeof LcevcDil !== 'undefined' &&
|
|
115
|
-
typeof libDPIModule !== 'undefined' &&
|
|
116
|
-
this.canvas_ instanceof HTMLCanvasElement &&
|
|
117
|
-
LcevcDil.SupportObject.SupportStatus;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Update current active variant
|
|
122
|
-
* @param {shaka.extern.Track} track
|
|
123
|
-
*/
|
|
124
|
-
updateVariant(track) {
|
|
125
|
-
let containerFormat = shaka.lcevc.Dil.ContainerFormat.MPEG2_TS;
|
|
126
|
-
switch (track.mimeType) {
|
|
127
|
-
case 'video/webm': {
|
|
128
|
-
containerFormat = shaka.lcevc.Dil.ContainerFormat.WEBM;
|
|
129
|
-
break;
|
|
130
|
-
}
|
|
131
|
-
case 'video/mp4': {
|
|
132
|
-
containerFormat = shaka.lcevc.Dil.ContainerFormat.MP4;
|
|
133
|
-
break;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
if (this.dil_) {
|
|
137
|
-
this.variantId_ = track.id;
|
|
138
|
-
this.dil_.setLevelSwitching(track.id, true);
|
|
139
|
-
this.dil_.setContainerFormat(containerFormat);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Container Formats.
|
|
146
|
-
* @const @enum {number}
|
|
147
|
-
*/
|
|
148
|
-
shaka.lcevc.Dil.ContainerFormat = {
|
|
149
|
-
MPEG2_TS: 0,
|
|
150
|
-
WEBM: 1,
|
|
151
|
-
MP4: 2,
|
|
152
|
-
};
|
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
/*! @license
|
|
2
|
-
* Shaka Player
|
|
3
|
-
* Copyright 2016 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
goog.provide('shaka.transmuxer.MuxjsTransmuxer');
|
|
8
|
-
|
|
9
|
-
goog.require('goog.asserts');
|
|
10
|
-
goog.require('shaka.dependencies');
|
|
11
|
-
goog.require('shaka.media.Capabilities');
|
|
12
|
-
goog.require('shaka.transmuxer.TransmuxerEngine');
|
|
13
|
-
goog.require('shaka.util.BufferUtils');
|
|
14
|
-
goog.require('shaka.util.Error');
|
|
15
|
-
goog.require('shaka.util.ManifestParserUtils');
|
|
16
|
-
goog.require('shaka.util.PublicPromise');
|
|
17
|
-
goog.require('shaka.util.Uint8ArrayUtils');
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* @implements {shaka.extern.Transmuxer}
|
|
22
|
-
* @export
|
|
23
|
-
*/
|
|
24
|
-
shaka.transmuxer.MuxjsTransmuxer = class {
|
|
25
|
-
/**
|
|
26
|
-
* @param {string} mimeType
|
|
27
|
-
*/
|
|
28
|
-
constructor(mimeType) {
|
|
29
|
-
/** @private {string} */
|
|
30
|
-
this.originalMimeType_ = mimeType;
|
|
31
|
-
|
|
32
|
-
/** @private {?muxjs} */
|
|
33
|
-
this.muxjs_ = shaka.dependencies.muxjs();
|
|
34
|
-
|
|
35
|
-
/** @private {muxjs.mp4.Transmuxer} */
|
|
36
|
-
this.muxTransmuxer_ = null;
|
|
37
|
-
|
|
38
|
-
/** @private {shaka.util.PublicPromise} */
|
|
39
|
-
this.transmuxPromise_ = null;
|
|
40
|
-
|
|
41
|
-
/** @private {!Array.<!Uint8Array>} */
|
|
42
|
-
this.transmuxedData_ = [];
|
|
43
|
-
|
|
44
|
-
/** @private {boolean} */
|
|
45
|
-
this.isTransmuxing_ = false;
|
|
46
|
-
|
|
47
|
-
if (this.muxjs_) {
|
|
48
|
-
this.muxTransmuxer_ = new this.muxjs_.mp4.Transmuxer({
|
|
49
|
-
'keepOriginalTimestamps': true,
|
|
50
|
-
});
|
|
51
|
-
this.muxTransmuxer_.on('data', (segment) => this.onTransmuxed_(segment));
|
|
52
|
-
this.muxTransmuxer_.on('done', () => this.onTransmuxDone_());
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* @override
|
|
59
|
-
* @export
|
|
60
|
-
*/
|
|
61
|
-
destroy() {
|
|
62
|
-
if (this.muxTransmuxer_) {
|
|
63
|
-
this.muxTransmuxer_.dispose();
|
|
64
|
-
}
|
|
65
|
-
this.muxTransmuxer_ = null;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Check if the mime type and the content type is supported.
|
|
71
|
-
* @param {string} mimeType
|
|
72
|
-
* @param {string=} contentType
|
|
73
|
-
* @return {boolean}
|
|
74
|
-
* @override
|
|
75
|
-
* @export
|
|
76
|
-
*/
|
|
77
|
-
isSupported(mimeType, contentType) {
|
|
78
|
-
const Capabilities = shaka.media.Capabilities;
|
|
79
|
-
|
|
80
|
-
const isTs = this.isTsContainer_(mimeType);
|
|
81
|
-
|
|
82
|
-
if (!this.muxjs_ || !isTs) {
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (contentType) {
|
|
87
|
-
return Capabilities.isTypeSupported(
|
|
88
|
-
this.convertTsCodecs_(contentType, mimeType));
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
92
|
-
|
|
93
|
-
const audioMime = this.convertTsCodecs_(ContentType.AUDIO, mimeType);
|
|
94
|
-
const videoMime = this.convertTsCodecs_(ContentType.VIDEO, mimeType);
|
|
95
|
-
return Capabilities.isTypeSupported(audioMime) ||
|
|
96
|
-
Capabilities.isTypeSupported(videoMime);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Check if the mimetype contains 'mp2t'.
|
|
102
|
-
* @param {string} mimeType
|
|
103
|
-
* @return {boolean}
|
|
104
|
-
* @private
|
|
105
|
-
*/
|
|
106
|
-
isTsContainer_(mimeType) {
|
|
107
|
-
return mimeType.toLowerCase().split(';')[0].split('/')[1] == 'mp2t';
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* @override
|
|
113
|
-
* @export
|
|
114
|
-
*/
|
|
115
|
-
convertCodecs(contentType, mimeType) {
|
|
116
|
-
if (this.isTsContainer_(mimeType)) {
|
|
117
|
-
return this.convertTsCodecs_(contentType, mimeType);
|
|
118
|
-
}
|
|
119
|
-
return mimeType;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* For transport stream, convert its codecs to MP4 codecs.
|
|
125
|
-
* @param {string} contentType
|
|
126
|
-
* @param {string} tsMimeType
|
|
127
|
-
* @return {string}
|
|
128
|
-
* @private
|
|
129
|
-
*/
|
|
130
|
-
convertTsCodecs_(contentType, tsMimeType) {
|
|
131
|
-
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
132
|
-
let mp4MimeType = tsMimeType.replace(/mp2t/i, 'mp4');
|
|
133
|
-
if (contentType == ContentType.AUDIO) {
|
|
134
|
-
mp4MimeType = mp4MimeType.replace('video', 'audio');
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Handle legacy AVC1 codec strings (pre-RFC 6381).
|
|
138
|
-
// Look for "avc1.<profile>.<level>", where profile is:
|
|
139
|
-
// 66 (baseline => 0x42)
|
|
140
|
-
// 77 (main => 0x4d)
|
|
141
|
-
// 100 (high => 0x64)
|
|
142
|
-
// Reference: https://bit.ly/2K9JI3x
|
|
143
|
-
const match = /avc1\.(66|77|100)\.(\d+)/.exec(mp4MimeType);
|
|
144
|
-
if (match) {
|
|
145
|
-
let newCodecString = 'avc1.';
|
|
146
|
-
|
|
147
|
-
const profile = match[1];
|
|
148
|
-
if (profile == '66') {
|
|
149
|
-
newCodecString += '4200';
|
|
150
|
-
} else if (profile == '77') {
|
|
151
|
-
newCodecString += '4d00';
|
|
152
|
-
} else {
|
|
153
|
-
goog.asserts.assert(profile == '100',
|
|
154
|
-
'Legacy avc1 parsing code out of sync with regex!');
|
|
155
|
-
newCodecString += '6400';
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Convert the level to hex and append to the codec string.
|
|
159
|
-
const level = Number(match[2]);
|
|
160
|
-
goog.asserts.assert(level < 256,
|
|
161
|
-
'Invalid legacy avc1 level number!');
|
|
162
|
-
newCodecString += (level >> 4).toString(16);
|
|
163
|
-
newCodecString += (level & 0xf).toString(16);
|
|
164
|
-
|
|
165
|
-
mp4MimeType = mp4MimeType.replace(match[0], newCodecString);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return mp4MimeType;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* @override
|
|
174
|
-
* @export
|
|
175
|
-
*/
|
|
176
|
-
getOrginalMimeType() {
|
|
177
|
-
return this.originalMimeType_;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* @override
|
|
183
|
-
* @export
|
|
184
|
-
*/
|
|
185
|
-
transmux(data) {
|
|
186
|
-
goog.asserts.assert(this.muxTransmuxer_,
|
|
187
|
-
'mux.js should be available.');
|
|
188
|
-
goog.asserts.assert(!this.isTransmuxing_,
|
|
189
|
-
'No transmuxing should be in progress.');
|
|
190
|
-
this.isTransmuxing_ = true;
|
|
191
|
-
this.transmuxPromise_ = new shaka.util.PublicPromise();
|
|
192
|
-
this.transmuxedData_ = [];
|
|
193
|
-
|
|
194
|
-
const dataArray = shaka.util.BufferUtils.toUint8(data);
|
|
195
|
-
this.muxTransmuxer_.push(dataArray);
|
|
196
|
-
this.muxTransmuxer_.flush();
|
|
197
|
-
|
|
198
|
-
// Workaround for https://bit.ly/Shaka1449 mux.js not
|
|
199
|
-
// emitting 'data' and 'done' events.
|
|
200
|
-
// mux.js code is synchronous, so if onTransmuxDone_ has
|
|
201
|
-
// not been called by now, it's not going to be.
|
|
202
|
-
// Treat it as a transmuxing failure and reject the promise.
|
|
203
|
-
if (this.isTransmuxing_) {
|
|
204
|
-
this.transmuxPromise_.reject(new shaka.util.Error(
|
|
205
|
-
shaka.util.Error.Severity.CRITICAL,
|
|
206
|
-
shaka.util.Error.Category.MEDIA,
|
|
207
|
-
shaka.util.Error.Code.TRANSMUXING_FAILED));
|
|
208
|
-
}
|
|
209
|
-
return this.transmuxPromise_;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Handles the 'data' event of the transmuxer.
|
|
214
|
-
* Extracts the cues from the transmuxed segment, and adds them to an array.
|
|
215
|
-
* Stores the transmuxed data in another array, to pass it back to
|
|
216
|
-
* MediaSourceEngine, and append to the source buffer.
|
|
217
|
-
*
|
|
218
|
-
* @param {muxjs.mp4.Transmuxer.Segment} segment
|
|
219
|
-
* @private
|
|
220
|
-
*/
|
|
221
|
-
onTransmuxed_(segment) {
|
|
222
|
-
this.transmuxedData_.push(
|
|
223
|
-
shaka.util.Uint8ArrayUtils.concat(segment.initSegment, segment.data));
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Handles the 'done' event of the transmuxer.
|
|
229
|
-
* Resolves the transmux Promise, and returns the transmuxed data.
|
|
230
|
-
* @private
|
|
231
|
-
*/
|
|
232
|
-
onTransmuxDone_() {
|
|
233
|
-
const data = shaka.util.Uint8ArrayUtils.concat(...this.transmuxedData_);
|
|
234
|
-
this.transmuxPromise_.resolve(data);
|
|
235
|
-
this.isTransmuxing_ = false;
|
|
236
|
-
}
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
shaka.transmuxer.TransmuxerEngine.registerTransmuxer(
|
|
240
|
-
'video/mp2t',
|
|
241
|
-
() => new shaka.transmuxer.MuxjsTransmuxer('video/mp2t'),
|
|
242
|
-
shaka.transmuxer.TransmuxerEngine.PluginPriority.FALLBACK);
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
/*! @license
|
|
2
|
-
* Shaka Player
|
|
3
|
-
* Copyright 2016 Google LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
describe('MuxjsTransmuxer', () => {
|
|
8
|
-
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
9
|
-
|
|
10
|
-
const videoSegmentUri = '/base/test/test/assets/video.ts';
|
|
11
|
-
const audioSegmentUri = '/base/test/test/assets/audio.ts';
|
|
12
|
-
const mp4MimeType = 'video/mp4; codecs="avc1.42E01E"';
|
|
13
|
-
const transportStreamVideoMimeType = 'video/mp2t; codecs="avc1.42E01E"';
|
|
14
|
-
const transportStreamAudioMimeType = 'video/mp2t; codecs="mp4a.40.2"';
|
|
15
|
-
|
|
16
|
-
/** @type {!ArrayBuffer} */
|
|
17
|
-
let videoSegment;
|
|
18
|
-
/** @type {!ArrayBuffer} */
|
|
19
|
-
let audioSegment;
|
|
20
|
-
/** @type {!ArrayBuffer} */
|
|
21
|
-
let emptySegment;
|
|
22
|
-
|
|
23
|
-
/** @type {?shaka.transmuxer.MuxjsTransmuxer} */
|
|
24
|
-
let transmuxer;
|
|
25
|
-
|
|
26
|
-
function useTsTransmuxer() {
|
|
27
|
-
transmuxer = new shaka.transmuxer.MuxjsTransmuxer('video/mp2t');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
beforeAll(async () => {
|
|
31
|
-
const responses = await Promise.all([
|
|
32
|
-
shaka.test.Util.fetch(videoSegmentUri),
|
|
33
|
-
shaka.test.Util.fetch(audioSegmentUri),
|
|
34
|
-
]);
|
|
35
|
-
videoSegment = responses[0];
|
|
36
|
-
audioSegment = responses[1];
|
|
37
|
-
emptySegment = new ArrayBuffer(0);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
beforeEach(() => {
|
|
41
|
-
transmuxer = null;
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
afterEach(async () => {
|
|
45
|
-
await transmuxer.destroy();
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
describe('isSupported', () => {
|
|
49
|
-
it('returns whether the content type is supported', () => {
|
|
50
|
-
useTsTransmuxer();
|
|
51
|
-
expect(transmuxer.isSupported(
|
|
52
|
-
mp4MimeType, ContentType.VIDEO)).toBe(false);
|
|
53
|
-
expect(transmuxer.isSupported(
|
|
54
|
-
transportStreamVideoMimeType, ContentType.VIDEO)).toBe(true);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
// Issue #1991
|
|
58
|
-
it('handles upper-case MIME types', () => {
|
|
59
|
-
useTsTransmuxer();
|
|
60
|
-
const mimeType = transportStreamVideoMimeType.replace('mp2t', 'MP2T');
|
|
61
|
-
expect(transmuxer.isSupported(
|
|
62
|
-
mimeType, ContentType.VIDEO)).toBe(true);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
describe('convertCodecs', () => {
|
|
67
|
-
const convertCodecs =
|
|
68
|
-
(type, codecs) => transmuxer.convertCodecs(type, codecs);
|
|
69
|
-
|
|
70
|
-
it('returns converted codecs for TS', () => {
|
|
71
|
-
useTsTransmuxer();
|
|
72
|
-
const convertedVideoCodecs =
|
|
73
|
-
convertCodecs(ContentType.VIDEO, transportStreamVideoMimeType);
|
|
74
|
-
const convertedAudioCodecs =
|
|
75
|
-
convertCodecs(ContentType.AUDIO, transportStreamAudioMimeType);
|
|
76
|
-
const expectedVideoCodecs = 'video/mp4; codecs="avc1.42E01E"';
|
|
77
|
-
const expectedAudioCodecs = 'audio/mp4; codecs="mp4a.40.2"';
|
|
78
|
-
expect(convertedVideoCodecs).toBe(expectedVideoCodecs);
|
|
79
|
-
expect(convertedAudioCodecs).toBe(expectedAudioCodecs);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('converts legacy avc1 codec strings', () => {
|
|
83
|
-
useTsTransmuxer();
|
|
84
|
-
expect(
|
|
85
|
-
convertCodecs(
|
|
86
|
-
ContentType.VIDEO, 'video/mp2t; codecs="avc1.100.42"'))
|
|
87
|
-
.toBe('video/mp4; codecs="avc1.64002a"');
|
|
88
|
-
expect(
|
|
89
|
-
convertCodecs(ContentType.VIDEO, 'video/mp2t; codecs="avc1.77.80"'))
|
|
90
|
-
.toBe('video/mp4; codecs="avc1.4d0050"');
|
|
91
|
-
expect(
|
|
92
|
-
convertCodecs(ContentType.VIDEO, 'video/mp2t; codecs="avc1.66.1"'))
|
|
93
|
-
.toBe('video/mp4; codecs="avc1.420001"');
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
// Issue #1991
|
|
97
|
-
it('handles upper-case MIME types', () => {
|
|
98
|
-
useTsTransmuxer();
|
|
99
|
-
expect(convertCodecs(
|
|
100
|
-
ContentType.VIDEO, 'video/MP2T; codecs="avc1.420001"'))
|
|
101
|
-
.toBe('video/mp4; codecs="avc1.420001"');
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
describe('transmuxing', () => {
|
|
106
|
-
it('transmux video from TS to MP4', async () => {
|
|
107
|
-
useTsTransmuxer();
|
|
108
|
-
let sawMDAT = false;
|
|
109
|
-
|
|
110
|
-
const transmuxedData = await transmuxer.transmux(videoSegment);
|
|
111
|
-
expect(transmuxedData).toEqual(jasmine.any(Uint8Array));
|
|
112
|
-
expect(transmuxedData.length).toBeGreaterThan(0);
|
|
113
|
-
new shaka.util.Mp4Parser()
|
|
114
|
-
.box('mdat', shaka.util.Mp4Parser.allData((data) => {
|
|
115
|
-
sawMDAT = true;
|
|
116
|
-
expect(data.byteLength).toBeGreaterThan(0);
|
|
117
|
-
}))
|
|
118
|
-
.parse(transmuxedData);
|
|
119
|
-
expect(sawMDAT).toBeTruthy();
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('transmux audio from TS to MP4', async () => {
|
|
123
|
-
useTsTransmuxer();
|
|
124
|
-
let sawMDAT = false;
|
|
125
|
-
const transmuxedData = await transmuxer.transmux(audioSegment);
|
|
126
|
-
expect(transmuxedData).toEqual(jasmine.any(Uint8Array));
|
|
127
|
-
expect(transmuxedData.length).toBeGreaterThan(0);
|
|
128
|
-
new shaka.util.Mp4Parser()
|
|
129
|
-
.box('mdat', shaka.util.Mp4Parser.allData((data) => {
|
|
130
|
-
sawMDAT = true;
|
|
131
|
-
expect(data.byteLength).toBeGreaterThan(0);
|
|
132
|
-
}))
|
|
133
|
-
.parse(transmuxedData);
|
|
134
|
-
expect(sawMDAT).toBeTruthy();
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('transmux empty video from TS to MP4', async () => {
|
|
138
|
-
useTsTransmuxer();
|
|
139
|
-
let sawMDAT = false;
|
|
140
|
-
const transmuxedData = await transmuxer.transmux(emptySegment);
|
|
141
|
-
expect(transmuxedData).toEqual(jasmine.any(Uint8Array));
|
|
142
|
-
new shaka.util.Mp4Parser()
|
|
143
|
-
.box('mdat', shaka.util.Mp4Parser.allData((data) => {
|
|
144
|
-
sawMDAT = true;
|
|
145
|
-
}))
|
|
146
|
-
.parse(transmuxedData);
|
|
147
|
-
expect(sawMDAT).toBeFalsy();
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('passes through true timestamps', async () => {
|
|
151
|
-
useTsTransmuxer();
|
|
152
|
-
let parsed = false;
|
|
153
|
-
const expectedMp4Timestamp = 5166000; // in timescale units
|
|
154
|
-
let mp4Timestamp;
|
|
155
|
-
|
|
156
|
-
const transmuxedData = await transmuxer.transmux(videoSegment);
|
|
157
|
-
const Mp4Parser = shaka.util.Mp4Parser;
|
|
158
|
-
|
|
159
|
-
new Mp4Parser()
|
|
160
|
-
.box('moof', Mp4Parser.children)
|
|
161
|
-
.box('traf', Mp4Parser.children)
|
|
162
|
-
.fullBox('tfdt', (box) => {
|
|
163
|
-
goog.asserts.assert(
|
|
164
|
-
box.version == 0 || box.version == 1,
|
|
165
|
-
'TFDT version can only be 0 or 1');
|
|
166
|
-
const parsedTFDTBox = shaka.util.Mp4BoxParsers.parseTFDT(
|
|
167
|
-
box.reader, box.version);
|
|
168
|
-
mp4Timestamp = parsedTFDTBox.baseMediaDecodeTime;
|
|
169
|
-
parsed = true;
|
|
170
|
-
})
|
|
171
|
-
.parse(transmuxedData);
|
|
172
|
-
|
|
173
|
-
expect(parsed).toBe(true);
|
|
174
|
-
expect(mp4Timestamp).toBe(expectedMp4Timestamp);
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
});
|