shaka-player 4.3.11 → 4.4.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.
- package/AUTHORS +9 -0
- package/CHANGELOG.md +303 -202
- package/CONTRIBUTORS +8 -0
- package/LICENSE +32 -0
- package/README.md +63 -10
- package/demo/autoTemplate.txt +40 -5
- package/demo/close_button.js +11 -0
- package/demo/common/asset.js +13 -1
- package/demo/common/assets.js +53 -3
- package/demo/common/message_ids.js +25 -1
- package/demo/config.js +69 -10
- package/demo/customWarning.txt +2 -2
- package/demo/index.html +3 -1
- package/demo/locales/en.json +26 -2
- package/demo/locales/source.json +105 -9
- package/demo/main.js +52 -9
- package/demo/search.js +3 -1
- package/demo/service_worker.js +3 -0
- package/dist/controls.css +1 -1
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +124 -112
- package/dist/demo.compiled.debug.map +3 -3
- package/dist/demo.compiled.js +124 -112
- package/dist/demo.compiled.map +3 -3
- package/dist/deps.js +46 -28
- package/dist/locales.js +33 -33
- package/dist/receiver.compiled.debug.js +52 -46
- package/dist/receiver.compiled.debug.map +3 -3
- package/dist/receiver.compiled.js +52 -46
- package/dist/receiver.compiled.map +3 -3
- package/dist/shaka-player.compiled.d.ts +676 -391
- package/dist/shaka-player.compiled.debug.d.ts +676 -391
- package/dist/shaka-player.compiled.debug.externs.js +1188 -616
- package/dist/shaka-player.compiled.debug.js +1043 -699
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +1188 -616
- package/dist/shaka-player.compiled.js +1091 -929
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +677 -392
- package/dist/shaka-player.ui.debug.d.ts +677 -392
- package/dist/shaka-player.ui.debug.externs.js +1023 -451
- package/dist/shaka-player.ui.debug.js +1098 -737
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +1023 -451
- package/dist/shaka-player.ui.js +1246 -1071
- package/dist/shaka-player.ui.map +4 -4
- package/docs/tutorials/ad_monetization.md +15 -1
- package/docs/tutorials/application-level-redirects.md +1 -1
- package/docs/tutorials/config.md +9 -5
- package/docs/tutorials/drm-config.md +61 -0
- package/docs/tutorials/fairplay.md +19 -4
- package/docs/tutorials/license-server-auth.md +4 -4
- package/docs/tutorials/license-wrapping.md +2 -2
- package/docs/tutorials/ui-customization.md +7 -3
- package/docs/tutorials/ui.md +7 -7
- package/docs/tutorials/upgrade.md +3 -0
- package/externs/ima.js +123 -2
- package/externs/isoboxer.js +217 -0
- package/externs/mediakeys.js +18 -0
- package/externs/mux.js +1 -105
- package/externs/pictureinpicture.js +48 -0
- package/externs/shaka/ads.js +61 -1
- package/externs/shaka/cea.js +110 -0
- package/externs/shaka/codecs.js +32 -0
- package/externs/shaka/manifest.js +101 -1
- package/externs/shaka/manifest_parser.js +0 -10
- package/externs/shaka/net.js +36 -7
- package/externs/shaka/offline.js +8 -1
- package/externs/shaka/player.js +220 -21
- package/externs/shaka/text.js +1 -382
- package/externs/shaka/transmuxer.js +60 -0
- package/karma.conf.js +13 -0
- package/lib/abr/simple_abr_manager.js +6 -3
- package/lib/ads/ad_manager.js +60 -2
- package/lib/ads/client_side_ad.js +86 -0
- package/lib/ads/client_side_ad_manager.js +79 -3
- package/lib/ads/server_side_ad.js +86 -0
- package/lib/ads/server_side_ad_manager.js +13 -0
- package/lib/cast/cast_utils.js +1 -0
- package/lib/cea/cea608_data_channel.js +24 -14
- package/lib/cea/cea608_memory.js +5 -2
- package/lib/cea/cea708_service.js +8 -9
- package/lib/cea/cea708_window.js +1 -2
- package/lib/cea/cea_decoder.js +23 -6
- package/lib/cea/cea_utils.js +25 -2
- package/lib/cea/dummy_caption_decoder.js +21 -0
- package/lib/cea/dummy_cea_parser.js +1 -3
- package/lib/cea/mp4_cea_parser.js +15 -10
- package/lib/cea/ts_cea_parser.js +69 -0
- package/lib/dash/content_protection.js +32 -2
- package/lib/dash/dash_parser.js +93 -31
- package/lib/dash/mpd_utils.js +6 -25
- package/lib/dash/segment_base.js +12 -14
- package/lib/dash/segment_list.js +10 -6
- package/lib/dash/segment_template.js +349 -32
- package/lib/dependencies/all.js +8 -0
- package/lib/hls/hls_classes.js +33 -8
- package/lib/hls/hls_parser.js +805 -191
- package/lib/hls/manifest_text_parser.js +4 -14
- package/lib/media/adaptation_set_criteria.js +43 -3
- package/lib/media/closed_caption_parser.js +74 -12
- package/lib/media/drm_engine.js +189 -49
- package/lib/media/gap_jumping_controller.js +1 -1
- package/lib/media/manifest_parser.js +34 -0
- package/lib/media/media_source_capabilities.js +10 -0
- package/lib/media/media_source_engine.js +495 -231
- package/lib/media/playhead.js +1 -1
- package/lib/media/presentation_timeline.js +62 -0
- package/lib/media/segment_index.js +50 -14
- package/lib/media/segment_prefetch.js +277 -0
- package/lib/media/segment_reference.js +70 -4
- package/lib/media/streaming_engine.js +258 -81
- package/lib/media/video_wrapper.js +15 -7
- package/lib/mss/content_protection.js +353 -0
- package/lib/mss/mss_parser.js +1082 -0
- package/lib/net/networking_engine.js +60 -10
- 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 +6 -0
- package/lib/offline/storage.js +2 -4
- package/lib/player.js +309 -105
- package/lib/polyfill/media_capabilities.js +43 -3
- package/lib/polyfill/patchedmediakeys_apple.js +5 -0
- package/lib/polyfill/patchedmediakeys_nop.js +5 -0
- package/lib/polyfill/patchedmediakeys_webkit.js +5 -0
- package/lib/text/cue.js +208 -130
- package/lib/text/lrc_text_parser.js +2 -2
- package/lib/text/mp4_vtt_parser.js +2 -2
- package/lib/text/sbv_text_parser.js +1 -1
- package/lib/text/simple_text_displayer.js +1 -1
- package/lib/text/srt_text_parser.js +9 -1
- package/lib/text/ssa_text_parser.js +2 -2
- package/lib/text/text_engine.js +3 -21
- package/lib/text/text_utils.js +71 -20
- package/lib/text/ui_text_displayer.js +14 -14
- package/lib/text/vtt_text_parser.js +22 -14
- package/lib/transmuxer/aac_transmuxer.js +224 -0
- package/lib/transmuxer/ac3.js +142 -0
- package/lib/transmuxer/ac3_transmuxer.js +213 -0
- package/lib/transmuxer/adts.js +232 -0
- package/lib/transmuxer/ec3.js +103 -0
- package/lib/transmuxer/ec3_transmuxer.js +213 -0
- package/lib/transmuxer/h264.js +324 -0
- package/lib/transmuxer/mp3_transmuxer.js +205 -0
- package/lib/transmuxer/mpeg_audio.js +196 -0
- package/lib/transmuxer/mpeg_ts_transmuxer.js +182 -0
- package/lib/transmuxer/mss_transmuxer.js +389 -0
- package/lib/{media/transmuxer.js → transmuxer/muxjs_transmuxer.js} +34 -80
- package/lib/transmuxer/transmuxer_engine.js +161 -0
- package/lib/transmuxer/ts_transmuxer.js +721 -0
- package/lib/util/cmcd_manager.js +131 -71
- package/lib/util/error.js +62 -26
- package/lib/util/exp_golomb.js +220 -0
- package/lib/util/fairplay_utils.js +64 -13
- package/lib/util/id3_utils.js +56 -3
- package/lib/util/language_utils.js +11 -8
- package/lib/util/manifest_parser_utils.js +3 -0
- package/lib/util/mime_utils.js +44 -7
- package/lib/util/mp4_box_parsers.js +233 -5
- package/lib/util/mp4_generator.js +1388 -0
- package/lib/util/periods.js +40 -34
- package/lib/util/platform.js +17 -3
- package/lib/util/player_configuration.js +38 -1
- package/lib/util/stream_utils.js +138 -27
- package/lib/util/text_parser.js +1 -1
- package/lib/util/ts_parser.js +460 -74
- package/lib/util/xml_utils.js +16 -3
- package/maintained-branches.md +2 -2
- package/package.json +3 -1
- package/roadmap.md +21 -6
- package/shaka-player.uncompiled.js +18 -0
- package/test/abr/simple_abr_manager_unit.js +32 -4
- package/test/ads/ad_manager_unit.js +18 -2
- package/test/cast/cast_utils_unit.js +7 -2
- package/test/cea/cea608_memory_unit.js +24 -0
- package/test/cea/cea_decoder_unit.js +33 -0
- package/test/dash/dash_parser_content_protection_unit.js +93 -3
- package/test/dash/dash_parser_live_unit.js +56 -13
- package/test/dash/dash_parser_manifest_unit.js +70 -2
- package/test/dash/dash_parser_segment_base_unit.js +14 -9
- package/test/dash/dash_parser_segment_template_unit.js +286 -6
- package/test/demo/demo_unit.js +5 -1
- package/test/hls/hls_live_unit.js +188 -28
- package/test/hls/hls_parser_unit.js +250 -109
- package/test/hls/manifest_text_parser_unit.js +18 -13
- package/test/media/adaptation_set_criteria_unit.js +46 -14
- package/test/media/adaptation_set_unit.js +2 -0
- package/test/media/drm_engine_integration.js +11 -8
- package/test/media/drm_engine_unit.js +220 -7
- package/test/media/media_source_engine_integration.js +124 -40
- package/test/media/media_source_engine_unit.js +133 -153
- package/test/media/playhead_unit.js +3 -0
- package/test/media/presentation_timeline_unit.js +51 -0
- package/test/media/segment_index_unit.js +52 -0
- package/test/media/segment_prefetch_unit.js +243 -0
- package/test/media/streaming_engine_integration.js +9 -3
- package/test/media/streaming_engine_unit.js +440 -59
- package/test/mss/mss_parser_content_protection_unit.js +49 -0
- package/test/mss/mss_parser_unit.js +472 -0
- package/test/mss/mss_player_integration.js +123 -0
- package/test/offline/manifest_convert_unit.js +9 -0
- package/test/offline/storage_integration.js +6 -1
- package/test/player_unit.js +386 -133
- package/test/polyfill/media_capabilities_unit.js +18 -0
- package/test/test/assets/hls-raw-aac/fileSequence0.aac +0 -0
- package/test/test/assets/hls-raw-aac/fileSequence1.aac +0 -0
- package/test/test/assets/hls-raw-aac/fileSequence2.aac +0 -0
- package/test/test/assets/hls-raw-aac/fileSequence3.aac +0 -0
- package/test/test/assets/hls-raw-aac/manifest.m3u8 +4 -0
- package/test/test/assets/hls-raw-aac/stream.m4a.m3u8 +14 -0
- package/test/test/assets/hls-raw-ac3/fileSequence0.ac3 +0 -0
- package/test/test/assets/hls-raw-ac3/fileSequence1.ac3 +0 -0
- package/test/test/assets/hls-raw-ac3/fileSequence2.ac3 +0 -0
- package/test/test/assets/hls-raw-ac3/fileSequence3.ac3 +0 -0
- package/test/test/assets/hls-raw-ac3/fileSequence4.ac3 +0 -0
- package/test/test/assets/hls-raw-ac3/fileSequence5.ac3 +0 -0
- package/test/test/assets/hls-raw-ac3/fileSequence6.ac3 +0 -0
- package/test/test/assets/hls-raw-ac3/fileSequence7.ac3 +0 -0
- package/test/test/assets/hls-raw-ac3/prog_index.m3u8 +31 -0
- package/test/test/assets/hls-raw-ec3/fileSequence0.ec3 +0 -0
- package/test/test/assets/hls-raw-ec3/fileSequence1.ec3 +0 -0
- package/test/test/assets/hls-raw-ec3/fileSequence2.ec3 +0 -0
- package/test/test/assets/hls-raw-ec3/fileSequence3.ec3 +0 -0
- package/test/test/assets/hls-raw-ec3/fileSequence4.ec3 +0 -0
- package/test/test/assets/hls-raw-ec3/fileSequence5.ec3 +0 -0
- package/test/test/assets/hls-raw-ec3/fileSequence6.ec3 +0 -0
- package/test/test/assets/hls-raw-ec3/fileSequence7.ec3 +0 -0
- package/test/test/assets/hls-raw-ec3/prog_index.m3u8 +31 -0
- package/test/test/assets/hls-raw-mp3/chunklist_w905519204.m3u8 +13 -0
- package/test/test/assets/hls-raw-mp3/media_w905519204_0.mp3 +0 -0
- package/test/test/assets/hls-raw-mp3/media_w905519204_1.mp3 +0 -0
- package/test/test/assets/hls-raw-mp3/media_w905519204_2.mp3 +0 -0
- package/test/test/assets/hls-raw-mp3/media_w905519204_3.mp3 +0 -0
- package/test/test/assets/hls-raw-mp3/playlist.m3u8 +4 -0
- package/test/test/assets/hls-ts-aac/playlist.m3u8 +23 -0
- package/test/test/assets/hls-ts-aac/segment_0.ts +0 -0
- package/test/test/assets/hls-ts-aac/segment_1.ts +0 -0
- package/test/test/assets/hls-ts-aac/segment_2.ts +0 -0
- package/test/test/assets/hls-ts-aac/segment_3.ts +0 -0
- package/test/test/assets/hls-ts-aac/segment_4.ts +0 -0
- package/test/test/assets/hls-ts-aac/segment_5.ts +0 -0
- package/test/test/assets/hls-ts-aac/segment_6.ts +0 -0
- package/test/test/assets/hls-ts-aac/segment_7.ts +0 -0
- package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0000.ts +0 -0
- package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0001.ts +0 -0
- package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0002.ts +0 -0
- package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0003.ts +0 -0
- package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0004.ts +0 -0
- package/test/test/assets/hls-ts-ac3/ChID_voices_6ch_640kbps_dd_sub_0005.ts +0 -0
- package/test/test/assets/hls-ts-ac3/prog_index.m3u8 +19 -0
- package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0000.ts +0 -0
- package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0001.ts +0 -0
- package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0002.ts +0 -0
- package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0003.ts +0 -0
- package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0004.ts +0 -0
- package/test/test/assets/hls-ts-ec3/ChID_voices_6ch_256kbps_ddp_sub_0005.ts +0 -0
- package/test/test/assets/hls-ts-ec3/prog_index.m3u8 +19 -0
- package/test/test/assets/hls-ts-h264/fileSequence0.ts +0 -0
- package/test/test/assets/hls-ts-h264/fileSequence1.ts +0 -0
- package/test/test/assets/hls-ts-h264/fileSequence2.ts +0 -0
- package/test/test/assets/hls-ts-h264/fileSequence3.ts +0 -0
- package/test/test/assets/hls-ts-h264/fileSequence4.ts +0 -0
- package/test/test/assets/hls-ts-h264/fileSequence5.ts +0 -0
- package/test/test/assets/hls-ts-h264/prog_index.m3u8 +25 -0
- package/test/test/assets/hls-ts-mp3/manifest.m3u8 +13 -0
- package/test/test/assets/hls-ts-mp3/media_w239891843_0.ts +0 -0
- package/test/test/assets/hls-ts-mp3/media_w239891843_1.ts +0 -0
- package/test/test/assets/hls-ts-mp3/media_w239891843_2.ts +0 -0
- package/test/test/assets/hls-ts-mp3/media_w239891843_3.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h264/chunk.m3u8 +17 -0
- package/test/test/assets/hls-ts-muxed-aac-h264/n_0_0_0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h264/n_1_0_0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h264/n_2_0_0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h264/n_3_0_0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h264/n_4_0_0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h264/n_5_0_0.ts +0 -0
- package/test/test/assets/hls-ts-muxed-aac-h264/playlist.m3u8 +4 -0
- package/test/test/boot.js +7 -2
- package/test/test/util/fake_ad.js +99 -0
- package/test/test/util/fake_ad_manager.js +7 -1
- package/test/test/util/fake_networking_engine.js +41 -14
- package/test/test/util/fake_segment_prefetch.js +81 -0
- package/test/test/util/manifest_generator.js +19 -5
- package/test/test/util/mss_parser_util.js +115 -0
- package/test/test/util/offline_utils.js +1 -0
- package/test/test/util/simple_fakes.js +12 -3
- package/test/test/util/streaming_engine_util.js +14 -4
- package/test/test/util/ttml_utils.js +2 -2
- package/test/text/cue_integration.js +1 -1
- package/test/text/srt_text_parser_unit.js +78 -0
- package/test/text/text_engine_unit.js +17 -8
- package/test/text/ui_text_displayer_unit.js +4 -4
- package/test/text/vtt_text_parser_unit.js +59 -40
- package/test/text/web_vtt_generator_unit.js +9 -3
- package/test/{media/transmuxer_integration.js → transmuxer/muxjs_transmuxer_integration.js} +30 -33
- package/test/transmuxer/transmuxer_engine_integration.js +60 -0
- package/test/transmuxer/transmuxer_integration.js +296 -0
- package/test/util/cmcd_manager_unit.js +162 -13
- package/test/util/language_utils_unit.js +9 -2
- package/test/util/mp4_box_parsers_unit.js +39 -4
- package/test/util/periods_unit.js +34 -26
- package/test/util/stream_utils_unit.js +60 -107
- package/ui/controls.js +19 -1
- package/ui/controls.less +1 -0
- package/ui/externs/ui.js +11 -1
- package/ui/language_utils.js +15 -0
- package/ui/less/thumbnails.less +26 -0
- package/ui/locales/oc.json +42 -0
- package/ui/pip_button.js +83 -2
- package/ui/range_element.js +15 -0
- package/ui/resolution_selection.js +9 -2
- package/ui/seek_bar.js +223 -0
- package/ui/ui.js +5 -0
- package/lib/cea/i_caption_decoder.js +0 -51
- package/lib/cea/i_cea_parser.js +0 -68
package/lib/util/ts_parser.js
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
goog.provide('shaka.util.TsParser');
|
|
8
8
|
|
|
9
|
-
goog.require('goog.asserts');
|
|
10
9
|
goog.require('shaka.log');
|
|
10
|
+
goog.require('shaka.util.ExpGolomb');
|
|
11
11
|
goog.require('shaka.util.Id3Utils');
|
|
12
12
|
goog.require('shaka.util.Uint8ArrayUtils');
|
|
13
13
|
|
|
@@ -25,9 +25,6 @@ shaka.util.TsParser = class {
|
|
|
25
25
|
/** @private {boolean} */
|
|
26
26
|
this.pmtParsed_ = false;
|
|
27
27
|
|
|
28
|
-
/** @private {?number} */
|
|
29
|
-
this.videoStartTime_ = null;
|
|
30
|
-
|
|
31
28
|
/** @private {?number} */
|
|
32
29
|
this.videoPid_ = null;
|
|
33
30
|
|
|
@@ -37,9 +34,6 @@ shaka.util.TsParser = class {
|
|
|
37
34
|
/** @private {!Array.<Uint8Array>} */
|
|
38
35
|
this.videoData_ = [];
|
|
39
36
|
|
|
40
|
-
/** @private {?number} */
|
|
41
|
-
this.audioStartTime_ = null;
|
|
42
|
-
|
|
43
37
|
/** @private {?number} */
|
|
44
38
|
this.audioPid_ = null;
|
|
45
39
|
|
|
@@ -56,15 +50,27 @@ shaka.util.TsParser = class {
|
|
|
56
50
|
this.id3Data_ = [];
|
|
57
51
|
}
|
|
58
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Clear previous data
|
|
55
|
+
*
|
|
56
|
+
* @export
|
|
57
|
+
*/
|
|
58
|
+
clearData() {
|
|
59
|
+
this.videoData_ = [];
|
|
60
|
+
this.audioData_ = [];
|
|
61
|
+
this.id3Data_ = [];
|
|
62
|
+
}
|
|
63
|
+
|
|
59
64
|
/**
|
|
60
65
|
* Parse the given data
|
|
61
66
|
*
|
|
62
67
|
* @param {Uint8Array} data
|
|
63
68
|
* @return {!shaka.util.TsParser}
|
|
69
|
+
* @export
|
|
64
70
|
*/
|
|
65
71
|
parse(data) {
|
|
66
|
-
const timescale = shaka.util.TsParser.Timescale_;
|
|
67
72
|
const packetLength = shaka.util.TsParser.PacketLength_;
|
|
73
|
+
const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
|
|
68
74
|
|
|
69
75
|
// A TS fragment should contain at least 3 TS packets, a PAT, a PMT, and
|
|
70
76
|
// one PID.
|
|
@@ -79,7 +85,7 @@ shaka.util.TsParser = class {
|
|
|
79
85
|
|
|
80
86
|
// loop through TS packets
|
|
81
87
|
for (let start = syncOffset; start < length; start += packetLength) {
|
|
82
|
-
if (data[start]
|
|
88
|
+
if (data[start] == 0x47) {
|
|
83
89
|
const payloadUnitStartIndicator = !!(data[start + 1] & 0x40);
|
|
84
90
|
// pid is a 13-bit field starting at the last 5 bits of TS[1]
|
|
85
91
|
const pid = ((data[start + 1] & 0x1f) << 8) + data[start + 2];
|
|
@@ -91,7 +97,7 @@ shaka.util.TsParser = class {
|
|
|
91
97
|
if (adaptationFieldControl > 1) {
|
|
92
98
|
offset = start + 5 + data[start + 4];
|
|
93
99
|
// continue if there is only adaptation field
|
|
94
|
-
if (offset
|
|
100
|
+
if (offset == start + packetLength) {
|
|
95
101
|
continue;
|
|
96
102
|
}
|
|
97
103
|
} else {
|
|
@@ -113,7 +119,7 @@ shaka.util.TsParser = class {
|
|
|
113
119
|
offset += data[offset] + 1;
|
|
114
120
|
}
|
|
115
121
|
|
|
116
|
-
const parsedPIDs = this.
|
|
122
|
+
const parsedPIDs = this.parsePMT_(data, offset);
|
|
117
123
|
|
|
118
124
|
// only update track id if track PID found while parsing PMT
|
|
119
125
|
// this is to avoid resetting the PID to -1 in case
|
|
@@ -146,29 +152,43 @@ shaka.util.TsParser = class {
|
|
|
146
152
|
}
|
|
147
153
|
case this.videoPid_: {
|
|
148
154
|
const videoData = data.subarray(offset, start + packetLength);
|
|
149
|
-
if (
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
155
|
+
if (payloadUnitStartIndicator) {
|
|
156
|
+
this.videoData_.push(videoData);
|
|
157
|
+
} else if (this.videoData_.length) {
|
|
158
|
+
const prevVideoData = this.videoData_[this.videoData_.length - 1];
|
|
159
|
+
if (prevVideoData) {
|
|
160
|
+
this.videoData_[this.videoData_.length - 1] =
|
|
161
|
+
Uint8ArrayUtils.concat(prevVideoData, videoData);
|
|
153
162
|
}
|
|
154
163
|
}
|
|
155
|
-
this.videoData_.push(videoData);
|
|
156
164
|
break;
|
|
157
165
|
}
|
|
158
166
|
case this.audioPid_: {
|
|
159
167
|
const audioData = data.subarray(offset, start + packetLength);
|
|
160
|
-
if (
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
168
|
+
if (payloadUnitStartIndicator) {
|
|
169
|
+
this.audioData_.push(audioData);
|
|
170
|
+
} else if (this.audioData_.length) {
|
|
171
|
+
const prevAudioData = this.audioData_[this.audioData_.length - 1];
|
|
172
|
+
if (prevAudioData) {
|
|
173
|
+
this.audioData_[this.audioData_.length - 1] =
|
|
174
|
+
Uint8ArrayUtils.concat(prevAudioData, audioData);
|
|
164
175
|
}
|
|
165
176
|
}
|
|
166
|
-
this.audioData_.push(audioData);
|
|
167
177
|
break;
|
|
168
178
|
}
|
|
169
|
-
case this.id3Pid_:
|
|
170
|
-
|
|
179
|
+
case this.id3Pid_: {
|
|
180
|
+
const id3Data = data.subarray(offset, start + packetLength);
|
|
181
|
+
if (payloadUnitStartIndicator) {
|
|
182
|
+
this.id3Data_.push(id3Data);
|
|
183
|
+
} else if (this.id3Data_.length) {
|
|
184
|
+
const prevId3Data = this.id3Data_[this.id3Data_.length - 1];
|
|
185
|
+
if (prevId3Data) {
|
|
186
|
+
this.id3Data_[this.id3Data_.length - 1] =
|
|
187
|
+
Uint8ArrayUtils.concat(prevId3Data, id3Data);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
171
190
|
break;
|
|
191
|
+
}
|
|
172
192
|
default:
|
|
173
193
|
unknownPIDs = true;
|
|
174
194
|
break;
|
|
@@ -199,8 +219,9 @@ shaka.util.TsParser = class {
|
|
|
199
219
|
* @param {Uint8Array} data
|
|
200
220
|
* @param {number} offset
|
|
201
221
|
* @return {!shaka.util.TsParser.PMT}
|
|
222
|
+
* @private
|
|
202
223
|
*/
|
|
203
|
-
|
|
224
|
+
parsePMT_(data, offset) {
|
|
204
225
|
const result = {
|
|
205
226
|
audio: -1,
|
|
206
227
|
video: -1,
|
|
@@ -218,20 +239,49 @@ shaka.util.TsParser = class {
|
|
|
218
239
|
offset += 12 + programInfoLength;
|
|
219
240
|
while (offset < tableEnd) {
|
|
220
241
|
const pid = ((data[offset + 1] & 0x1f) << 8) | data[offset + 2];
|
|
242
|
+
const esInfoLength = ((data[offset + 3] & 0x0f) << 8) | data[offset + 4];
|
|
221
243
|
switch (data[offset]) {
|
|
244
|
+
case 0x06:
|
|
245
|
+
// stream_type 6 can mean a lot of different things in case of DVB.
|
|
246
|
+
// We need to look at the descriptors. Right now, we're only
|
|
247
|
+
// interested in AC-3 and EC-3 audio, so we do the descriptor parsing
|
|
248
|
+
// only when we don't have an audio PID yet.
|
|
249
|
+
if (result.audio == -1 && esInfoLength > 0) {
|
|
250
|
+
let parsePos = offset + 5;
|
|
251
|
+
let remaining = esInfoLength;
|
|
252
|
+
while (remaining > 2) {
|
|
253
|
+
const descriptorId = data[parsePos];
|
|
254
|
+
switch (descriptorId) {
|
|
255
|
+
// DVB Descriptor for AC-3
|
|
256
|
+
case 0x6a:
|
|
257
|
+
result.audio = pid;
|
|
258
|
+
result.audioCodec = 'ac3';
|
|
259
|
+
break;
|
|
260
|
+
// DVB Descriptor for EC-3
|
|
261
|
+
case 0x7a:
|
|
262
|
+
result.audio = pid;
|
|
263
|
+
result.audioCodec = 'ec3';
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
const descriptorLen = data[parsePos + 1] + 2;
|
|
267
|
+
parsePos += descriptorLen;
|
|
268
|
+
remaining -= descriptorLen;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
break;
|
|
222
272
|
// SAMPLE-AES AAC
|
|
223
273
|
case 0xcf:
|
|
224
274
|
break;
|
|
225
275
|
// ISO/IEC 13818-7 ADTS AAC (MPEG-2 lower bit-rate audio)
|
|
226
276
|
case 0x0f:
|
|
227
|
-
if (result.audio
|
|
277
|
+
if (result.audio == -1) {
|
|
228
278
|
result.audio = pid;
|
|
229
279
|
result.audioCodec = 'aac';
|
|
230
280
|
}
|
|
231
281
|
break;
|
|
232
282
|
// Packetized metadata (ID3)
|
|
233
283
|
case 0x15:
|
|
234
|
-
if (result.id3
|
|
284
|
+
if (result.id3 == -1) {
|
|
235
285
|
result.id3 = pid;
|
|
236
286
|
}
|
|
237
287
|
break;
|
|
@@ -240,7 +290,7 @@ shaka.util.TsParser = class {
|
|
|
240
290
|
break;
|
|
241
291
|
// ITU-T Rec. H.264 and ISO/IEC 14496-10 (lower bit-rate video)
|
|
242
292
|
case 0x1b:
|
|
243
|
-
if (result.video
|
|
293
|
+
if (result.video == -1) {
|
|
244
294
|
result.video = pid;
|
|
245
295
|
result.videoCodec = 'avc';
|
|
246
296
|
}
|
|
@@ -249,25 +299,40 @@ shaka.util.TsParser = class {
|
|
|
249
299
|
// or ISO/IEC 13818-3 (MPEG-2 halved sample rate audio)
|
|
250
300
|
case 0x03:
|
|
251
301
|
case 0x04:
|
|
252
|
-
if (result.audio
|
|
302
|
+
if (result.audio == -1) {
|
|
253
303
|
result.audio = pid;
|
|
254
304
|
result.audioCodec = 'mp3';
|
|
255
305
|
}
|
|
256
306
|
break;
|
|
257
307
|
// HEVC
|
|
258
308
|
case 0x24:
|
|
259
|
-
if (result.video
|
|
309
|
+
if (result.video == -1) {
|
|
260
310
|
result.video = pid;
|
|
261
311
|
result.videoCodec = 'hvc';
|
|
262
312
|
}
|
|
263
313
|
break;
|
|
314
|
+
// AC-3
|
|
315
|
+
case 0x81:
|
|
316
|
+
if (result.audio == -1) {
|
|
317
|
+
result.audio = pid;
|
|
318
|
+
result.audioCodec = 'ac3';
|
|
319
|
+
}
|
|
320
|
+
break;
|
|
321
|
+
// EC-3
|
|
322
|
+
case 0x84:
|
|
323
|
+
case 0x87:
|
|
324
|
+
if (result.audio == -1) {
|
|
325
|
+
result.audio = pid;
|
|
326
|
+
result.audioCodec = 'ec3';
|
|
327
|
+
}
|
|
328
|
+
break;
|
|
264
329
|
default:
|
|
265
330
|
// shaka.log.warning('Unknown stream type:', data[offset]);
|
|
266
331
|
break;
|
|
267
332
|
}
|
|
268
333
|
// move to the next table entry
|
|
269
334
|
// skip past the elementary stream descriptors, if present
|
|
270
|
-
offset +=
|
|
335
|
+
offset += esInfoLength + 5;
|
|
271
336
|
}
|
|
272
337
|
return result;
|
|
273
338
|
}
|
|
@@ -276,9 +341,10 @@ shaka.util.TsParser = class {
|
|
|
276
341
|
* Parse PES
|
|
277
342
|
*
|
|
278
343
|
* @param {Uint8Array} data
|
|
279
|
-
* @return {?shaka.
|
|
344
|
+
* @return {?shaka.extern.MPEG_PES}
|
|
345
|
+
* @private
|
|
280
346
|
*/
|
|
281
|
-
|
|
347
|
+
parsePES_(data) {
|
|
282
348
|
const startPrefix = (data[0] << 16) | (data[1] << 8) | data[2];
|
|
283
349
|
// In certain live streams, the start of a TS fragment has ts packets
|
|
284
350
|
// that are frame data that is continuing from the previous fragment. This
|
|
@@ -286,11 +352,11 @@ shaka.util.TsParser = class {
|
|
|
286
352
|
if (startPrefix !== 1) {
|
|
287
353
|
return null;
|
|
288
354
|
}
|
|
289
|
-
/** @type {shaka.
|
|
355
|
+
/** @type {shaka.extern.MPEG_PES} */
|
|
290
356
|
const pes = {
|
|
291
357
|
data: new Uint8Array(0),
|
|
292
358
|
// get the packet length, this will be 0 for video
|
|
293
|
-
packetLength:
|
|
359
|
+
packetLength: ((data[4] << 8) | data[5]),
|
|
294
360
|
pts: null,
|
|
295
361
|
dts: null,
|
|
296
362
|
};
|
|
@@ -337,51 +403,217 @@ shaka.util.TsParser = class {
|
|
|
337
403
|
return pes;
|
|
338
404
|
}
|
|
339
405
|
|
|
406
|
+
/**
|
|
407
|
+
* Parse AVC Nalus
|
|
408
|
+
*
|
|
409
|
+
* The code is based on hls.js
|
|
410
|
+
* Credit to https://github.com/video-dev/hls.js/blob/master/src/demux/tsdemuxer.ts
|
|
411
|
+
*
|
|
412
|
+
* @param {shaka.extern.MPEG_PES} pes
|
|
413
|
+
* @param {?shaka.extern.MPEG_PES=} nextPes
|
|
414
|
+
* @return {!Array.<shaka.extern.VideoNalu>}
|
|
415
|
+
* @export
|
|
416
|
+
*/
|
|
417
|
+
parseAvcNalus(pes, nextPes) {
|
|
418
|
+
const timescale = shaka.util.TsParser.Timescale;
|
|
419
|
+
const time = pes.pts ? pes.pts / timescale : null;
|
|
420
|
+
let data = pes.data;
|
|
421
|
+
let len = data.byteLength;
|
|
422
|
+
|
|
423
|
+
// A NALU does not contain is its size.
|
|
424
|
+
// The Annex B specification solves this by requiring ‘Start Codes’ to
|
|
425
|
+
// precede each NALU. A start code is 2 or 3 0x00 bytes followed with a
|
|
426
|
+
// 0x01 byte. e.g. 0x000001 or 0x00000001.
|
|
427
|
+
// More info in: https://stackoverflow.com/questions/24884827/possible-locations-for-sequence-picture-parameter-sets-for-h-264-stream/24890903#24890903
|
|
428
|
+
let numZeros = 0;
|
|
429
|
+
|
|
430
|
+
/** @type {!Array.<shaka.extern.VideoNalu>} */
|
|
431
|
+
const nalus = [];
|
|
432
|
+
|
|
433
|
+
// Start position includes the first byte where we read the type.
|
|
434
|
+
// The data we extract begins at the next byte.
|
|
435
|
+
let lastNaluStart = -1;
|
|
436
|
+
// Extracted from the first byte.
|
|
437
|
+
let lastNaluType = 0;
|
|
438
|
+
|
|
439
|
+
let tryToFinishLastNalu = false;
|
|
440
|
+
|
|
441
|
+
/** @type {?shaka.extern.VideoNalu} */
|
|
442
|
+
let infoOfLastNalu;
|
|
443
|
+
|
|
444
|
+
for (let i = 0; i < len; ++i) {
|
|
445
|
+
const value = data[i];
|
|
446
|
+
if (!value) {
|
|
447
|
+
numZeros++;
|
|
448
|
+
} else if (numZeros >= 2 && value == 1 && tryToFinishLastNalu) {
|
|
449
|
+
// If we are scanning the next PES, we need append the data to the
|
|
450
|
+
// previous Nalu and don't scan for more nalus.
|
|
451
|
+
const startCodeSize = numZeros > 3 ? 3 : numZeros;
|
|
452
|
+
const lastByteToKeep = i - startCodeSize;
|
|
453
|
+
infoOfLastNalu.data = shaka.util.Uint8ArrayUtils.concat(
|
|
454
|
+
infoOfLastNalu.data, data.subarray(0, lastByteToKeep));
|
|
455
|
+
infoOfLastNalu.fullData = shaka.util.Uint8ArrayUtils.concat(
|
|
456
|
+
infoOfLastNalu.fullData, data.subarray(0, lastByteToKeep));
|
|
457
|
+
break;
|
|
458
|
+
} else if (numZeros >= 2 && value == 1) {
|
|
459
|
+
// We just read a start code. Consume the NALU we passed, if any.
|
|
460
|
+
if (lastNaluStart >= 0) {
|
|
461
|
+
// Because the start position includes the type, skip the first byte.
|
|
462
|
+
const firstByteToKeep = lastNaluStart + 1;
|
|
463
|
+
|
|
464
|
+
// Compute the last byte to keep. The start code is at most 3 zeros.
|
|
465
|
+
// Any earlier zeros are not part of the start code.
|
|
466
|
+
const startCodeSize = (numZeros > 3 ? 3 : numZeros) + 1;
|
|
467
|
+
const lastByteToKeep = i - startCodeSize;
|
|
468
|
+
|
|
469
|
+
/** @type {shaka.extern.VideoNalu} */
|
|
470
|
+
const nalu = {
|
|
471
|
+
// subarray's end position is exclusive, so add one.
|
|
472
|
+
data: data.subarray(firstByteToKeep, lastByteToKeep + 1),
|
|
473
|
+
fullData: data.subarray(lastNaluStart, lastByteToKeep + 1),
|
|
474
|
+
type: lastNaluType,
|
|
475
|
+
time: time,
|
|
476
|
+
};
|
|
477
|
+
nalus.push(nalu);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// We just read a start code, so there should be another byte here, at
|
|
481
|
+
// least, for the NALU type. Check just in case.
|
|
482
|
+
if (i >= len - 1) {
|
|
483
|
+
shaka.log.warning('Malformed TS, incomplete NALU, ignoring.');
|
|
484
|
+
return nalus;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Advance and read the type of the next NALU.
|
|
488
|
+
i++;
|
|
489
|
+
lastNaluStart = i;
|
|
490
|
+
lastNaluType = data[i] & 0x1f;
|
|
491
|
+
numZeros = 0;
|
|
492
|
+
} else {
|
|
493
|
+
numZeros = 0;
|
|
494
|
+
}
|
|
495
|
+
// If we have gone through all the data from the PES and we have an
|
|
496
|
+
// unfinished Nalu, we will try to use the next PES to complete the
|
|
497
|
+
// unfinished Nalu.
|
|
498
|
+
if (i >= (len - 1) && lastNaluStart >= 0 && numZeros >= 0) {
|
|
499
|
+
if (tryToFinishLastNalu) {
|
|
500
|
+
infoOfLastNalu.data = shaka.util.Uint8ArrayUtils.concat(
|
|
501
|
+
infoOfLastNalu.data, data);
|
|
502
|
+
infoOfLastNalu.fullData = shaka.util.Uint8ArrayUtils.concat(
|
|
503
|
+
infoOfLastNalu.fullData, data);
|
|
504
|
+
} else {
|
|
505
|
+
tryToFinishLastNalu = true;
|
|
506
|
+
// The rest of the buffer was a NALU.
|
|
507
|
+
// Because the start position includes the type, skip the first byte.
|
|
508
|
+
const firstByteToKeep = lastNaluStart + 1;
|
|
509
|
+
infoOfLastNalu = {
|
|
510
|
+
data: data.subarray(firstByteToKeep, len),
|
|
511
|
+
fullData: data.subarray(lastNaluStart, len),
|
|
512
|
+
type: lastNaluType,
|
|
513
|
+
time: time,
|
|
514
|
+
};
|
|
515
|
+
if (nextPes && pes.packetLength == 0) {
|
|
516
|
+
data = nextPes.data;
|
|
517
|
+
len = data.byteLength;
|
|
518
|
+
i = -1;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (infoOfLastNalu) {
|
|
525
|
+
nalus.push(infoOfLastNalu);
|
|
526
|
+
}
|
|
527
|
+
return nalus;
|
|
528
|
+
}
|
|
529
|
+
|
|
340
530
|
/**
|
|
341
531
|
* Return the ID3 metadata
|
|
342
532
|
*
|
|
343
533
|
* @return {!Array.<shaka.extern.ID3Metadata>}
|
|
534
|
+
* @export
|
|
344
535
|
*/
|
|
345
536
|
getMetadata() {
|
|
346
|
-
const timescale = shaka.util.TsParser.
|
|
347
|
-
const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
|
|
537
|
+
const timescale = shaka.util.TsParser.Timescale;
|
|
348
538
|
const metadata = [];
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
// Try the last data blob first, and if it doesn't begin on a
|
|
352
|
-
// PES boundary, prepend the previous blob and try again.
|
|
353
|
-
// This way, a successful parse will always begin and end on
|
|
354
|
-
// the correct boundary, and no data will be skipped.
|
|
355
|
-
for (let i = this.id3Data_.length - 1; i >= 0; i--) {
|
|
356
|
-
const data = this.id3Data_[i];
|
|
357
|
-
goog.asserts.assert(data, 'We should have a data');
|
|
358
|
-
const id3Data = Uint8ArrayUtils.concat(data, prevId3Data);
|
|
359
|
-
const pes = this.parsePES(id3Data);
|
|
539
|
+
for (const id3Data of this.id3Data_) {
|
|
540
|
+
const pes = this.parsePES_(id3Data);
|
|
360
541
|
if (pes) {
|
|
361
|
-
metadata.
|
|
542
|
+
metadata.push({
|
|
362
543
|
cueTime: pes.pts ? pes.pts / timescale : null,
|
|
363
544
|
data: pes.data,
|
|
364
545
|
frames: shaka.util.Id3Utils.getID3Frames(pes.data),
|
|
365
546
|
dts: pes.dts,
|
|
366
547
|
pts: pes.pts,
|
|
367
548
|
});
|
|
368
|
-
prevId3Data = new Uint8Array(0);
|
|
369
|
-
} else {
|
|
370
|
-
prevId3Data = id3Data;
|
|
371
549
|
}
|
|
372
550
|
}
|
|
373
551
|
return metadata;
|
|
374
552
|
}
|
|
375
553
|
|
|
554
|
+
/**
|
|
555
|
+
* Return the audio data
|
|
556
|
+
*
|
|
557
|
+
* @return {!Array.<shaka.extern.MPEG_PES>}
|
|
558
|
+
* @export
|
|
559
|
+
*/
|
|
560
|
+
getAudioData() {
|
|
561
|
+
const audio = [];
|
|
562
|
+
for (const audioData of this.audioData_) {
|
|
563
|
+
const pes = this.parsePES_(audioData);
|
|
564
|
+
if (pes) {
|
|
565
|
+
audio.push(pes);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return audio;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Return the audio data
|
|
573
|
+
*
|
|
574
|
+
* @return {!Array.<shaka.extern.MPEG_PES>}
|
|
575
|
+
* @export
|
|
576
|
+
*/
|
|
577
|
+
getVideoData() {
|
|
578
|
+
const video = [];
|
|
579
|
+
for (const videoData of this.videoData_) {
|
|
580
|
+
const pes = this.parsePES_(videoData);
|
|
581
|
+
if (pes) {
|
|
582
|
+
video.push(pes);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
return video;
|
|
586
|
+
}
|
|
587
|
+
|
|
376
588
|
/**
|
|
377
589
|
* Return the start time for the audio and video
|
|
378
590
|
*
|
|
379
591
|
* @return {{audio: ?number, video: ?number}}
|
|
592
|
+
* @export
|
|
380
593
|
*/
|
|
381
594
|
getStartTime() {
|
|
595
|
+
const timescale = shaka.util.TsParser.Timescale;
|
|
596
|
+
let audioStartTime = null;
|
|
597
|
+
for (const pes of this.getAudioData()) {
|
|
598
|
+
if (pes && pes.pts != null) {
|
|
599
|
+
const startTime = Math.min(pes.dts, pes.pts) / timescale;
|
|
600
|
+
if (audioStartTime == null || audioStartTime > startTime) {
|
|
601
|
+
audioStartTime = startTime;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
let videoStartTime = null;
|
|
606
|
+
for (const pes of this.getVideoData()) {
|
|
607
|
+
if (pes && pes.pts != null) {
|
|
608
|
+
const startTime = Math.min(pes.dts, pes.pts) / timescale;
|
|
609
|
+
if (videoStartTime == null || videoStartTime > startTime) {
|
|
610
|
+
videoStartTime = startTime;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
}
|
|
382
614
|
return {
|
|
383
|
-
audio:
|
|
384
|
-
video:
|
|
615
|
+
audio: audioStartTime,
|
|
616
|
+
video: videoStartTime,
|
|
385
617
|
};
|
|
386
618
|
}
|
|
387
619
|
|
|
@@ -389,6 +621,7 @@ shaka.util.TsParser = class {
|
|
|
389
621
|
* Return the audio and video codecs
|
|
390
622
|
*
|
|
391
623
|
* @return {{audio: ?string, video: ?string}}
|
|
624
|
+
* @export
|
|
392
625
|
*/
|
|
393
626
|
getCodecs() {
|
|
394
627
|
return {
|
|
@@ -397,11 +630,159 @@ shaka.util.TsParser = class {
|
|
|
397
630
|
};
|
|
398
631
|
}
|
|
399
632
|
|
|
633
|
+
/**
|
|
634
|
+
* Return the video data
|
|
635
|
+
*
|
|
636
|
+
* @return {!Array.<shaka.extern.VideoNalu>}
|
|
637
|
+
* @export
|
|
638
|
+
*/
|
|
639
|
+
getVideoNalus() {
|
|
640
|
+
const nalus = [];
|
|
641
|
+
if (this.videoCodec_ != 'avc') {
|
|
642
|
+
return nalus;
|
|
643
|
+
}
|
|
644
|
+
const videoData = this.getVideoData();
|
|
645
|
+
for (let i = 0; i < videoData.length; i++) {
|
|
646
|
+
const pes = videoData[i];
|
|
647
|
+
let nextPes;
|
|
648
|
+
if (i + 1 < videoData.length) {
|
|
649
|
+
nextPes = videoData[i + 1];
|
|
650
|
+
}
|
|
651
|
+
nalus.push(...this.parseAvcNalus(pes, nextPes));
|
|
652
|
+
}
|
|
653
|
+
return nalus;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Return the video resolution
|
|
658
|
+
*
|
|
659
|
+
* @return {{height: ?string, width: ?string}}
|
|
660
|
+
* @export
|
|
661
|
+
*/
|
|
662
|
+
getVideoResolution() {
|
|
663
|
+
const TsParser = shaka.util.TsParser;
|
|
664
|
+
const resolution = {
|
|
665
|
+
height: null,
|
|
666
|
+
width: null,
|
|
667
|
+
};
|
|
668
|
+
const videoNalus = this.getVideoNalus();
|
|
669
|
+
if (!videoNalus.length) {
|
|
670
|
+
return resolution;
|
|
671
|
+
}
|
|
672
|
+
const spsNalu = videoNalus.find((nalu) => {
|
|
673
|
+
return nalu.type == TsParser.H264_NALU_TYPE_SPS_;
|
|
674
|
+
});
|
|
675
|
+
if (!spsNalu) {
|
|
676
|
+
return resolution;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
const expGolombDecoder = new shaka.util.ExpGolomb(spsNalu.data);
|
|
680
|
+
// profile_idc
|
|
681
|
+
const profileIdc = expGolombDecoder.readUnsignedByte();
|
|
682
|
+
// constraint_set[0-5]_flag
|
|
683
|
+
expGolombDecoder.readUnsignedByte();
|
|
684
|
+
// level_idc u(8)
|
|
685
|
+
expGolombDecoder.readUnsignedByte();
|
|
686
|
+
// seq_parameter_set_id
|
|
687
|
+
expGolombDecoder.skipExpGolomb();
|
|
688
|
+
|
|
689
|
+
// some profiles have more optional data we don't need
|
|
690
|
+
if (TsParser.PROFILES_WITH_OPTIONAL_SPS_DATA_.includes(profileIdc)) {
|
|
691
|
+
const chromaFormatIdc = expGolombDecoder.readUnsignedExpGolomb();
|
|
692
|
+
if (chromaFormatIdc === 3) {
|
|
693
|
+
// separate_colour_plane_flag
|
|
694
|
+
expGolombDecoder.skipBits(1);
|
|
695
|
+
}
|
|
696
|
+
// bit_depth_luma_minus8
|
|
697
|
+
expGolombDecoder.skipExpGolomb();
|
|
698
|
+
// bit_depth_chroma_minus8
|
|
699
|
+
expGolombDecoder.skipExpGolomb();
|
|
700
|
+
// qpprime_y_zero_transform_bypass_flag
|
|
701
|
+
expGolombDecoder.skipBits(1);
|
|
702
|
+
// seq_scaling_matrix_present_flag
|
|
703
|
+
if (expGolombDecoder.readBoolean()) {
|
|
704
|
+
const scalingListCount = (chromaFormatIdc !== 3) ? 8 : 12;
|
|
705
|
+
for (let i = 0; i < scalingListCount; i++) {
|
|
706
|
+
// seq_scaling_list_present_flag[ i ]
|
|
707
|
+
if (expGolombDecoder.readBoolean()) {
|
|
708
|
+
if (i < 6) {
|
|
709
|
+
expGolombDecoder.skipScalingList(16);
|
|
710
|
+
} else {
|
|
711
|
+
expGolombDecoder.skipScalingList(64);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// log2_max_frame_num_minus4
|
|
719
|
+
expGolombDecoder.skipExpGolomb();
|
|
720
|
+
const picOrderCntType = expGolombDecoder.readUnsignedExpGolomb();
|
|
721
|
+
|
|
722
|
+
if (picOrderCntType === 0) {
|
|
723
|
+
// log2_max_pic_order_cnt_lsb_minus4
|
|
724
|
+
expGolombDecoder.readUnsignedExpGolomb();
|
|
725
|
+
} else if (picOrderCntType === 1) {
|
|
726
|
+
// delta_pic_order_always_zero_flag
|
|
727
|
+
expGolombDecoder.skipBits(1);
|
|
728
|
+
// offset_for_non_ref_pic
|
|
729
|
+
expGolombDecoder.skipExpGolomb();
|
|
730
|
+
// offset_for_top_to_bottom_field
|
|
731
|
+
expGolombDecoder.skipExpGolomb();
|
|
732
|
+
const numRefFramesInPicOrderCntCycle =
|
|
733
|
+
expGolombDecoder.readUnsignedExpGolomb();
|
|
734
|
+
for (let i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
|
|
735
|
+
// offset_for_ref_frame[ i ]
|
|
736
|
+
expGolombDecoder.skipExpGolomb();
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// max_num_ref_frames
|
|
741
|
+
expGolombDecoder.skipExpGolomb();
|
|
742
|
+
// gaps_in_frame_num_value_allowed_flag
|
|
743
|
+
expGolombDecoder.skipBits(1);
|
|
744
|
+
|
|
745
|
+
const picWidthInMbsMinus1 =
|
|
746
|
+
expGolombDecoder.readUnsignedExpGolomb();
|
|
747
|
+
const picHeightInMapUnitsMinus1 =
|
|
748
|
+
expGolombDecoder.readUnsignedExpGolomb();
|
|
749
|
+
|
|
750
|
+
const frameMbsOnlyFlag = expGolombDecoder.readBits(1);
|
|
751
|
+
if (frameMbsOnlyFlag === 0) {
|
|
752
|
+
// mb_adaptive_frame_field_flag
|
|
753
|
+
expGolombDecoder.skipBits(1);
|
|
754
|
+
}
|
|
755
|
+
// direct_8x8_inference_flag
|
|
756
|
+
expGolombDecoder.skipBits(1);
|
|
757
|
+
|
|
758
|
+
let frameCropLeftOffset = 0;
|
|
759
|
+
let frameCropRightOffset = 0;
|
|
760
|
+
let frameCropTopOffset = 0;
|
|
761
|
+
let frameCropBottomOffset = 0;
|
|
762
|
+
|
|
763
|
+
// frame_cropping_flag
|
|
764
|
+
if (expGolombDecoder.readBoolean()) {
|
|
765
|
+
frameCropLeftOffset = expGolombDecoder.readUnsignedExpGolomb();
|
|
766
|
+
frameCropRightOffset = expGolombDecoder.readUnsignedExpGolomb();
|
|
767
|
+
frameCropTopOffset = expGolombDecoder.readUnsignedExpGolomb();
|
|
768
|
+
frameCropBottomOffset = expGolombDecoder.readUnsignedExpGolomb();
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
resolution.height = String(((2 - frameMbsOnlyFlag) *
|
|
772
|
+
(picHeightInMapUnitsMinus1 + 1) * 16) - (frameCropTopOffset * 2) -
|
|
773
|
+
(frameCropBottomOffset * 2));
|
|
774
|
+
resolution.width = String(((picWidthInMbsMinus1 + 1) * 16) -
|
|
775
|
+
frameCropLeftOffset * 2 - frameCropRightOffset * 2);
|
|
776
|
+
|
|
777
|
+
return resolution;
|
|
778
|
+
}
|
|
779
|
+
|
|
400
780
|
/**
|
|
401
781
|
* Check if the passed data corresponds to an MPEG2-TS
|
|
402
782
|
*
|
|
403
783
|
* @param {Uint8Array} data
|
|
404
784
|
* @return {boolean}
|
|
785
|
+
* @export
|
|
405
786
|
*/
|
|
406
787
|
static probe(data) {
|
|
407
788
|
const syncOffset = shaka.util.TsParser.syncOffset(data);
|
|
@@ -421,6 +802,7 @@ shaka.util.TsParser = class {
|
|
|
421
802
|
*
|
|
422
803
|
* @param {Uint8Array} data
|
|
423
804
|
* @return {number}
|
|
805
|
+
* @export
|
|
424
806
|
*/
|
|
425
807
|
static syncOffset(data) {
|
|
426
808
|
const packetLength = shaka.util.TsParser.PacketLength_;
|
|
@@ -430,9 +812,9 @@ shaka.util.TsParser = class {
|
|
|
430
812
|
while (i < scanwindow) {
|
|
431
813
|
// a TS fragment should contain at least 3 TS packets, a PAT, a PMT, and
|
|
432
814
|
// one PID, each starting with 0x47
|
|
433
|
-
if (data[i]
|
|
434
|
-
data[i + packetLength]
|
|
435
|
-
data[i + 2 * packetLength]
|
|
815
|
+
if (data[i] == 0x47 &&
|
|
816
|
+
data[i + packetLength] == 0x47 &&
|
|
817
|
+
data[i + 2 * packetLength] == 0x47) {
|
|
436
818
|
return i;
|
|
437
819
|
} else {
|
|
438
820
|
i++;
|
|
@@ -443,6 +825,13 @@ shaka.util.TsParser = class {
|
|
|
443
825
|
};
|
|
444
826
|
|
|
445
827
|
|
|
828
|
+
/**
|
|
829
|
+
* @const {number}
|
|
830
|
+
* @export
|
|
831
|
+
*/
|
|
832
|
+
shaka.util.TsParser.Timescale = 90000;
|
|
833
|
+
|
|
834
|
+
|
|
446
835
|
/**
|
|
447
836
|
* @const {number}
|
|
448
837
|
* @private
|
|
@@ -451,10 +840,24 @@ shaka.util.TsParser.PacketLength_ = 188;
|
|
|
451
840
|
|
|
452
841
|
|
|
453
842
|
/**
|
|
843
|
+
* NALU type for Sequence Parameter Set (SPS) for H.264.
|
|
454
844
|
* @const {number}
|
|
455
845
|
* @private
|
|
456
846
|
*/
|
|
457
|
-
shaka.util.TsParser.
|
|
847
|
+
shaka.util.TsParser.H264_NALU_TYPE_SPS_ = 0x07;
|
|
848
|
+
|
|
849
|
+
|
|
850
|
+
/**
|
|
851
|
+
* Values of profile_idc that indicate additional fields are included in the
|
|
852
|
+
* SPS.
|
|
853
|
+
* see Recommendation ITU-T H.264 (4/2013)
|
|
854
|
+
* 7.3.2.1.1 Sequence parameter set data syntax
|
|
855
|
+
*
|
|
856
|
+
* @const {!Array.<number>}
|
|
857
|
+
* @private
|
|
858
|
+
*/
|
|
859
|
+
shaka.util.TsParser.PROFILES_WITH_OPTIONAL_SPS_DATA_ =
|
|
860
|
+
[100, 110, 122, 244, 44, 83, 86, 118, 128, 138, 139, 134];
|
|
458
861
|
|
|
459
862
|
|
|
460
863
|
/**
|
|
@@ -480,20 +883,3 @@ shaka.util.TsParser.Timescale_ = 90000;
|
|
|
480
883
|
*/
|
|
481
884
|
shaka.util.TsParser.PMT;
|
|
482
885
|
|
|
483
|
-
|
|
484
|
-
/**
|
|
485
|
-
* @typedef {{
|
|
486
|
-
* data: Uint8Array,
|
|
487
|
-
* packetLength: number,
|
|
488
|
-
* pts: ?number,
|
|
489
|
-
* dts: ?number
|
|
490
|
-
* }}
|
|
491
|
-
*
|
|
492
|
-
* @summary PES.
|
|
493
|
-
* @property {Uint8Array} data
|
|
494
|
-
* @property {number} packetLength
|
|
495
|
-
* @property {?number} pts
|
|
496
|
-
* @property {?number} dts
|
|
497
|
-
*/
|
|
498
|
-
shaka.util.TsParser.PES;
|
|
499
|
-
|