shaka-player 4.3.10 → 4.4.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 +7 -0
- package/AUTHORS +9 -0
- package/CHANGELOG.md +295 -200
- 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 +28 -28
- 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 +1045 -700
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +1188 -616
- package/dist/shaka-player.compiled.js +1094 -933
- 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 +1100 -739
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +1023 -451
- package/dist/shaka-player.ui.js +1244 -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 +59 -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 +475 -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 +1081 -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 +2 -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 +212 -0
- package/lib/transmuxer/adts.js +232 -0
- package/lib/transmuxer/ec3.js +103 -0
- package/lib/transmuxer/ec3_transmuxer.js +212 -0
- package/lib/transmuxer/h264.js +324 -0
- package/lib/transmuxer/mp3_transmuxer.js +204 -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 +738 -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 +1381 -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 +470 -47
- 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 +122 -38
- 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
|
@@ -8,6 +8,7 @@ goog.provide('shaka.util.TsParser');
|
|
|
8
8
|
|
|
9
9
|
goog.require('goog.asserts');
|
|
10
10
|
goog.require('shaka.log');
|
|
11
|
+
goog.require('shaka.util.ExpGolomb');
|
|
11
12
|
goog.require('shaka.util.Id3Utils');
|
|
12
13
|
goog.require('shaka.util.Uint8ArrayUtils');
|
|
13
14
|
|
|
@@ -56,14 +57,28 @@ shaka.util.TsParser = class {
|
|
|
56
57
|
this.id3Data_ = [];
|
|
57
58
|
}
|
|
58
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Clear previous data
|
|
62
|
+
*
|
|
63
|
+
* @export
|
|
64
|
+
*/
|
|
65
|
+
clearData() {
|
|
66
|
+
this.videoStartTime_ = null;
|
|
67
|
+
this.videoData_ = [];
|
|
68
|
+
this.audioStartTime_ = null;
|
|
69
|
+
this.audioData_ = [];
|
|
70
|
+
this.id3Data_ = [];
|
|
71
|
+
}
|
|
72
|
+
|
|
59
73
|
/**
|
|
60
74
|
* Parse the given data
|
|
61
75
|
*
|
|
62
76
|
* @param {Uint8Array} data
|
|
63
77
|
* @return {!shaka.util.TsParser}
|
|
78
|
+
* @export
|
|
64
79
|
*/
|
|
65
80
|
parse(data) {
|
|
66
|
-
const timescale = shaka.util.TsParser.
|
|
81
|
+
const timescale = shaka.util.TsParser.Timescale;
|
|
67
82
|
const packetLength = shaka.util.TsParser.PacketLength_;
|
|
68
83
|
|
|
69
84
|
// A TS fragment should contain at least 3 TS packets, a PAT, a PMT, and
|
|
@@ -79,7 +94,7 @@ shaka.util.TsParser = class {
|
|
|
79
94
|
|
|
80
95
|
// loop through TS packets
|
|
81
96
|
for (let start = syncOffset; start < length; start += packetLength) {
|
|
82
|
-
if (data[start]
|
|
97
|
+
if (data[start] == 0x47) {
|
|
83
98
|
const payloadUnitStartIndicator = !!(data[start + 1] & 0x40);
|
|
84
99
|
// pid is a 13-bit field starting at the last 5 bits of TS[1]
|
|
85
100
|
const pid = ((data[start + 1] & 0x1f) << 8) + data[start + 2];
|
|
@@ -91,7 +106,7 @@ shaka.util.TsParser = class {
|
|
|
91
106
|
if (adaptationFieldControl > 1) {
|
|
92
107
|
offset = start + 5 + data[start + 4];
|
|
93
108
|
// continue if there is only adaptation field
|
|
94
|
-
if (offset
|
|
109
|
+
if (offset == start + packetLength) {
|
|
95
110
|
continue;
|
|
96
111
|
}
|
|
97
112
|
} else {
|
|
@@ -113,7 +128,7 @@ shaka.util.TsParser = class {
|
|
|
113
128
|
offset += data[offset] + 1;
|
|
114
129
|
}
|
|
115
130
|
|
|
116
|
-
const parsedPIDs = this.
|
|
131
|
+
const parsedPIDs = this.parsePMT_(data, offset);
|
|
117
132
|
|
|
118
133
|
// only update track id if track PID found while parsing PMT
|
|
119
134
|
// this is to avoid resetting the PID to -1 in case
|
|
@@ -146,10 +161,12 @@ shaka.util.TsParser = class {
|
|
|
146
161
|
}
|
|
147
162
|
case this.videoPid_: {
|
|
148
163
|
const videoData = data.subarray(offset, start + packetLength);
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
164
|
+
const pes = this.parsePES_(videoData, /* isVideo= */ true);
|
|
165
|
+
if (pes && pes.pts != null) {
|
|
166
|
+
const startTime = Math.min(pes.dts, pes.pts) / timescale;
|
|
167
|
+
if (this.videoStartTime_ == null ||
|
|
168
|
+
this.videoStartTime_ > startTime) {
|
|
169
|
+
this.videoStartTime_ = startTime;
|
|
153
170
|
}
|
|
154
171
|
}
|
|
155
172
|
this.videoData_.push(videoData);
|
|
@@ -157,10 +174,12 @@ shaka.util.TsParser = class {
|
|
|
157
174
|
}
|
|
158
175
|
case this.audioPid_: {
|
|
159
176
|
const audioData = data.subarray(offset, start + packetLength);
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
177
|
+
const pes = this.parsePES_(audioData);
|
|
178
|
+
if (pes && pes.pts != null) {
|
|
179
|
+
const startTime = Math.min(pes.dts, pes.pts) / timescale;
|
|
180
|
+
if (this.audioStartTime_ == null ||
|
|
181
|
+
this.audioStartTime_ > startTime) {
|
|
182
|
+
this.audioStartTime_ = startTime;
|
|
164
183
|
}
|
|
165
184
|
}
|
|
166
185
|
this.audioData_.push(audioData);
|
|
@@ -199,8 +218,9 @@ shaka.util.TsParser = class {
|
|
|
199
218
|
* @param {Uint8Array} data
|
|
200
219
|
* @param {number} offset
|
|
201
220
|
* @return {!shaka.util.TsParser.PMT}
|
|
221
|
+
* @private
|
|
202
222
|
*/
|
|
203
|
-
|
|
223
|
+
parsePMT_(data, offset) {
|
|
204
224
|
const result = {
|
|
205
225
|
audio: -1,
|
|
206
226
|
video: -1,
|
|
@@ -218,20 +238,49 @@ shaka.util.TsParser = class {
|
|
|
218
238
|
offset += 12 + programInfoLength;
|
|
219
239
|
while (offset < tableEnd) {
|
|
220
240
|
const pid = ((data[offset + 1] & 0x1f) << 8) | data[offset + 2];
|
|
241
|
+
const esInfoLength = ((data[offset + 3] & 0x0f) << 8) | data[offset + 4];
|
|
221
242
|
switch (data[offset]) {
|
|
243
|
+
case 0x06:
|
|
244
|
+
// stream_type 6 can mean a lot of different things in case of DVB.
|
|
245
|
+
// We need to look at the descriptors. Right now, we're only
|
|
246
|
+
// interested in AC-3 and EC-3 audio, so we do the descriptor parsing
|
|
247
|
+
// only when we don't have an audio PID yet.
|
|
248
|
+
if (result.audio == -1 && esInfoLength > 0) {
|
|
249
|
+
let parsePos = offset + 5;
|
|
250
|
+
let remaining = esInfoLength;
|
|
251
|
+
while (remaining > 2) {
|
|
252
|
+
const descriptorId = data[parsePos];
|
|
253
|
+
switch (descriptorId) {
|
|
254
|
+
// DVB Descriptor for AC-3
|
|
255
|
+
case 0x6a:
|
|
256
|
+
result.audio = pid;
|
|
257
|
+
result.audioCodec = 'ac3';
|
|
258
|
+
break;
|
|
259
|
+
// DVB Descriptor for EC-3
|
|
260
|
+
case 0x7a:
|
|
261
|
+
result.audio = pid;
|
|
262
|
+
result.audioCodec = 'ec3';
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
const descriptorLen = data[parsePos + 1] + 2;
|
|
266
|
+
parsePos += descriptorLen;
|
|
267
|
+
remaining -= descriptorLen;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
break;
|
|
222
271
|
// SAMPLE-AES AAC
|
|
223
272
|
case 0xcf:
|
|
224
273
|
break;
|
|
225
274
|
// ISO/IEC 13818-7 ADTS AAC (MPEG-2 lower bit-rate audio)
|
|
226
275
|
case 0x0f:
|
|
227
|
-
if (result.audio
|
|
276
|
+
if (result.audio == -1) {
|
|
228
277
|
result.audio = pid;
|
|
229
278
|
result.audioCodec = 'aac';
|
|
230
279
|
}
|
|
231
280
|
break;
|
|
232
281
|
// Packetized metadata (ID3)
|
|
233
282
|
case 0x15:
|
|
234
|
-
if (result.id3
|
|
283
|
+
if (result.id3 == -1) {
|
|
235
284
|
result.id3 = pid;
|
|
236
285
|
}
|
|
237
286
|
break;
|
|
@@ -240,7 +289,7 @@ shaka.util.TsParser = class {
|
|
|
240
289
|
break;
|
|
241
290
|
// ITU-T Rec. H.264 and ISO/IEC 14496-10 (lower bit-rate video)
|
|
242
291
|
case 0x1b:
|
|
243
|
-
if (result.video
|
|
292
|
+
if (result.video == -1) {
|
|
244
293
|
result.video = pid;
|
|
245
294
|
result.videoCodec = 'avc';
|
|
246
295
|
}
|
|
@@ -249,25 +298,40 @@ shaka.util.TsParser = class {
|
|
|
249
298
|
// or ISO/IEC 13818-3 (MPEG-2 halved sample rate audio)
|
|
250
299
|
case 0x03:
|
|
251
300
|
case 0x04:
|
|
252
|
-
if (result.audio
|
|
301
|
+
if (result.audio == -1) {
|
|
253
302
|
result.audio = pid;
|
|
254
303
|
result.audioCodec = 'mp3';
|
|
255
304
|
}
|
|
256
305
|
break;
|
|
257
306
|
// HEVC
|
|
258
307
|
case 0x24:
|
|
259
|
-
if (result.video
|
|
308
|
+
if (result.video == -1) {
|
|
260
309
|
result.video = pid;
|
|
261
310
|
result.videoCodec = 'hvc';
|
|
262
311
|
}
|
|
263
312
|
break;
|
|
313
|
+
// AC-3
|
|
314
|
+
case 0x81:
|
|
315
|
+
if (result.audio == -1) {
|
|
316
|
+
result.audio = pid;
|
|
317
|
+
result.audioCodec = 'ac3';
|
|
318
|
+
}
|
|
319
|
+
break;
|
|
320
|
+
// EC-3
|
|
321
|
+
case 0x84:
|
|
322
|
+
case 0x87:
|
|
323
|
+
if (result.audio == -1) {
|
|
324
|
+
result.audio = pid;
|
|
325
|
+
result.audioCodec = 'ec3';
|
|
326
|
+
}
|
|
327
|
+
break;
|
|
264
328
|
default:
|
|
265
329
|
// shaka.log.warning('Unknown stream type:', data[offset]);
|
|
266
330
|
break;
|
|
267
331
|
}
|
|
268
332
|
// move to the next table entry
|
|
269
333
|
// skip past the elementary stream descriptors, if present
|
|
270
|
-
offset +=
|
|
334
|
+
offset += esInfoLength + 5;
|
|
271
335
|
}
|
|
272
336
|
return result;
|
|
273
337
|
}
|
|
@@ -276,9 +340,11 @@ shaka.util.TsParser = class {
|
|
|
276
340
|
* Parse PES
|
|
277
341
|
*
|
|
278
342
|
* @param {Uint8Array} data
|
|
279
|
-
* @
|
|
343
|
+
* @param {boolean=} isVideo
|
|
344
|
+
* @return {?shaka.extern.MPEG_PES}
|
|
345
|
+
* @private
|
|
280
346
|
*/
|
|
281
|
-
|
|
347
|
+
parsePES_(data, isVideo = false) {
|
|
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,15 +352,21 @@ 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
|
};
|
|
297
363
|
|
|
364
|
+
// If it is video, we expect the packet length to be 0. When the PES packet
|
|
365
|
+
// length is set to zero, the PES packet can be any length.
|
|
366
|
+
if (isVideo && pes.packetLength != 0) {
|
|
367
|
+
return null;
|
|
368
|
+
}
|
|
369
|
+
|
|
298
370
|
// PES packets may be annotated with a PTS value, or a PTS value
|
|
299
371
|
// and a DTS value. Determine what combination of values is
|
|
300
372
|
// available to work with.
|
|
@@ -337,17 +409,143 @@ shaka.util.TsParser = class {
|
|
|
337
409
|
return pes;
|
|
338
410
|
}
|
|
339
411
|
|
|
412
|
+
/**
|
|
413
|
+
* Parse AVC Nalus
|
|
414
|
+
*
|
|
415
|
+
* The code is based on hls.js
|
|
416
|
+
* Credit to https://github.com/video-dev/hls.js/blob/master/src/demux/tsdemuxer.ts
|
|
417
|
+
*
|
|
418
|
+
* @param {shaka.extern.MPEG_PES} pes
|
|
419
|
+
* @param {?shaka.extern.MPEG_PES=} nextPes
|
|
420
|
+
* @return {!Array.<shaka.extern.VideoNalu>}
|
|
421
|
+
* @export
|
|
422
|
+
*/
|
|
423
|
+
parseAvcNalus(pes, nextPes) {
|
|
424
|
+
const timescale = shaka.util.TsParser.Timescale;
|
|
425
|
+
const time = pes.pts ? pes.pts / timescale : null;
|
|
426
|
+
let data = pes.data;
|
|
427
|
+
let len = data.byteLength;
|
|
428
|
+
|
|
429
|
+
// A NALU does not contain is its size.
|
|
430
|
+
// The Annex B specification solves this by requiring ‘Start Codes’ to
|
|
431
|
+
// precede each NALU. A start code is 2 or 3 0x00 bytes followed with a
|
|
432
|
+
// 0x01 byte. e.g. 0x000001 or 0x00000001.
|
|
433
|
+
// More info in: https://stackoverflow.com/questions/24884827/possible-locations-for-sequence-picture-parameter-sets-for-h-264-stream/24890903#24890903
|
|
434
|
+
let numZeros = 0;
|
|
435
|
+
|
|
436
|
+
/** @type {!Array.<shaka.extern.VideoNalu>} */
|
|
437
|
+
const nalus = [];
|
|
438
|
+
|
|
439
|
+
// Start position includes the first byte where we read the type.
|
|
440
|
+
// The data we extract begins at the next byte.
|
|
441
|
+
let lastNaluStart = -1;
|
|
442
|
+
// Extracted from the first byte.
|
|
443
|
+
let lastNaluType = 0;
|
|
444
|
+
|
|
445
|
+
let tryToFinishLastNalu = false;
|
|
446
|
+
|
|
447
|
+
/** @type {?shaka.extern.VideoNalu} */
|
|
448
|
+
let infoOfLastNalu;
|
|
449
|
+
|
|
450
|
+
for (let i = 0; i < len; ++i) {
|
|
451
|
+
const value = data[i];
|
|
452
|
+
if (!value) {
|
|
453
|
+
numZeros++;
|
|
454
|
+
} else if (numZeros >= 2 && value == 1 && tryToFinishLastNalu) {
|
|
455
|
+
// If we are scanning the next PES, we need append the data to the
|
|
456
|
+
// previous Nalu and don't scan for more nalus.
|
|
457
|
+
if (i <= 2) {
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
infoOfLastNalu.data = shaka.util.Uint8ArrayUtils.concat(
|
|
461
|
+
infoOfLastNalu.data, data.subarray(0, i - 2));
|
|
462
|
+
infoOfLastNalu.fullData = shaka.util.Uint8ArrayUtils.concat(
|
|
463
|
+
infoOfLastNalu.fullData, data.subarray(0, i - 2));
|
|
464
|
+
break;
|
|
465
|
+
} else if (numZeros >= 2 && value == 1) {
|
|
466
|
+
// We just read a start code. Consume the NALU we passed, if any.
|
|
467
|
+
if (lastNaluStart >= 0) {
|
|
468
|
+
// Because the start position includes the type, skip the first byte.
|
|
469
|
+
const firstByteToKeep = lastNaluStart + 1;
|
|
470
|
+
|
|
471
|
+
// Compute the last byte to keep. The start code is at most 3 zeros.
|
|
472
|
+
// Any earlier zeros are not part of the start code.
|
|
473
|
+
const startCodeSize = (numZeros > 3 ? 3 : numZeros) + 1;
|
|
474
|
+
const lastByteToKeep = i - startCodeSize;
|
|
475
|
+
|
|
476
|
+
/** @type {shaka.extern.VideoNalu} */
|
|
477
|
+
const nalu = {
|
|
478
|
+
// subarray's end position is exclusive, so add one.
|
|
479
|
+
data: data.subarray(firstByteToKeep, lastByteToKeep + 1),
|
|
480
|
+
fullData: data.subarray(lastNaluStart, lastByteToKeep + 1),
|
|
481
|
+
type: lastNaluType,
|
|
482
|
+
time: time,
|
|
483
|
+
};
|
|
484
|
+
nalus.push(nalu);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// We just read a start code, so there should be another byte here, at
|
|
488
|
+
// least, for the NALU type. Check just in case.
|
|
489
|
+
if (i >= len - 1) {
|
|
490
|
+
shaka.log.warning('Malformed TS, incomplete NALU, ignoring.');
|
|
491
|
+
return nalus;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Advance and read the type of the next NALU.
|
|
495
|
+
i++;
|
|
496
|
+
lastNaluStart = i;
|
|
497
|
+
lastNaluType = data[i] & 0x1f;
|
|
498
|
+
numZeros = 0;
|
|
499
|
+
} else {
|
|
500
|
+
numZeros = 0;
|
|
501
|
+
}
|
|
502
|
+
// If we have gone through all the data from the PES and we have an
|
|
503
|
+
// unfinished Nalu, we will try to use the next PES to complete the
|
|
504
|
+
// unfinished Nalu.
|
|
505
|
+
if (i >= (len - 1) && lastNaluStart >= 0 && numZeros >= 0) {
|
|
506
|
+
if (tryToFinishLastNalu) {
|
|
507
|
+
infoOfLastNalu.data = shaka.util.Uint8ArrayUtils.concat(
|
|
508
|
+
infoOfLastNalu.data, data);
|
|
509
|
+
infoOfLastNalu.fullData = shaka.util.Uint8ArrayUtils.concat(
|
|
510
|
+
infoOfLastNalu.fullData, data);
|
|
511
|
+
} else {
|
|
512
|
+
tryToFinishLastNalu = true;
|
|
513
|
+
// The rest of the buffer was a NALU.
|
|
514
|
+
// Because the start position includes the type, skip the first byte.
|
|
515
|
+
const firstByteToKeep = lastNaluStart + 1;
|
|
516
|
+
infoOfLastNalu = {
|
|
517
|
+
data: data.subarray(firstByteToKeep, len),
|
|
518
|
+
fullData: data.subarray(lastNaluStart, len),
|
|
519
|
+
type: lastNaluType,
|
|
520
|
+
time: time,
|
|
521
|
+
};
|
|
522
|
+
if (nextPes) {
|
|
523
|
+
data = nextPes.data;
|
|
524
|
+
len = data.byteLength;
|
|
525
|
+
i = -1;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (infoOfLastNalu) {
|
|
532
|
+
nalus.push(infoOfLastNalu);
|
|
533
|
+
}
|
|
534
|
+
return nalus;
|
|
535
|
+
}
|
|
536
|
+
|
|
340
537
|
/**
|
|
341
538
|
* Return the ID3 metadata
|
|
342
539
|
*
|
|
343
540
|
* @return {!Array.<shaka.extern.ID3Metadata>}
|
|
541
|
+
* @export
|
|
344
542
|
*/
|
|
345
543
|
getMetadata() {
|
|
346
|
-
const timescale = shaka.util.TsParser.
|
|
544
|
+
const timescale = shaka.util.TsParser.Timescale;
|
|
347
545
|
const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
|
|
348
546
|
const metadata = [];
|
|
349
547
|
let prevId3Data = new Uint8Array(0);
|
|
350
|
-
//
|
|
548
|
+
// parsePES_() only works if the data begins on a PES boundary.
|
|
351
549
|
// Try the last data blob first, and if it doesn't begin on a
|
|
352
550
|
// PES boundary, prepend the previous blob and try again.
|
|
353
551
|
// This way, a successful parse will always begin and end on
|
|
@@ -356,7 +554,7 @@ shaka.util.TsParser = class {
|
|
|
356
554
|
const data = this.id3Data_[i];
|
|
357
555
|
goog.asserts.assert(data, 'We should have a data');
|
|
358
556
|
const id3Data = Uint8ArrayUtils.concat(data, prevId3Data);
|
|
359
|
-
const pes = this.
|
|
557
|
+
const pes = this.parsePES_(id3Data);
|
|
360
558
|
if (pes) {
|
|
361
559
|
metadata.unshift({
|
|
362
560
|
cueTime: pes.pts ? pes.pts / timescale : null,
|
|
@@ -373,10 +571,71 @@ shaka.util.TsParser = class {
|
|
|
373
571
|
return metadata;
|
|
374
572
|
}
|
|
375
573
|
|
|
574
|
+
/**
|
|
575
|
+
* Return the audio data
|
|
576
|
+
*
|
|
577
|
+
* @return {!Array.<shaka.extern.MPEG_PES>}
|
|
578
|
+
* @export
|
|
579
|
+
*/
|
|
580
|
+
getAudioData() {
|
|
581
|
+
const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
|
|
582
|
+
const audio = [];
|
|
583
|
+
let prevAudioData = new Uint8Array(0);
|
|
584
|
+
// parsePES_() only works if the data begins on a PES boundary.
|
|
585
|
+
// Try the last data blob first, and if it doesn't begin on a
|
|
586
|
+
// PES boundary, prepend the previous blob and try again.
|
|
587
|
+
// This way, a successful parse will always begin and end on
|
|
588
|
+
// the correct boundary, and no data will be skipped.
|
|
589
|
+
for (let i = this.audioData_.length - 1; i >= 0; i--) {
|
|
590
|
+
const data = this.audioData_[i];
|
|
591
|
+
goog.asserts.assert(data, 'We should have a data');
|
|
592
|
+
const audioData = Uint8ArrayUtils.concat(data, prevAudioData);
|
|
593
|
+
const pes = this.parsePES_(audioData);
|
|
594
|
+
if (pes) {
|
|
595
|
+
audio.unshift(pes);
|
|
596
|
+
prevAudioData = new Uint8Array(0);
|
|
597
|
+
} else {
|
|
598
|
+
prevAudioData = audioData;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
return audio;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Return the audio data
|
|
606
|
+
*
|
|
607
|
+
* @return {!Array.<shaka.extern.MPEG_PES>}
|
|
608
|
+
* @export
|
|
609
|
+
*/
|
|
610
|
+
getVideoData() {
|
|
611
|
+
const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
|
|
612
|
+
const video = [];
|
|
613
|
+
let prevVideoData = new Uint8Array(0);
|
|
614
|
+
// parsePES_() only works if the data begins on a PES boundary.
|
|
615
|
+
// Try the last data blob first, and if it doesn't begin on a
|
|
616
|
+
// PES boundary, prepend the previous blob and try again.
|
|
617
|
+
// This way, a successful parse will always begin and end on
|
|
618
|
+
// the correct boundary, and no data will be skipped.
|
|
619
|
+
for (let i = this.videoData_.length - 1; i >= 0; i--) {
|
|
620
|
+
const data = this.videoData_[i];
|
|
621
|
+
goog.asserts.assert(data, 'We should have a data');
|
|
622
|
+
const videoData = Uint8ArrayUtils.concat(data, prevVideoData);
|
|
623
|
+
const pes = this.parsePES_(videoData, /* isVideo= */ true);
|
|
624
|
+
if (pes) {
|
|
625
|
+
video.unshift(pes);
|
|
626
|
+
prevVideoData = new Uint8Array(0);
|
|
627
|
+
} else {
|
|
628
|
+
prevVideoData = videoData;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
return video;
|
|
632
|
+
}
|
|
633
|
+
|
|
376
634
|
/**
|
|
377
635
|
* Return the start time for the audio and video
|
|
378
636
|
*
|
|
379
637
|
* @return {{audio: ?number, video: ?number}}
|
|
638
|
+
* @export
|
|
380
639
|
*/
|
|
381
640
|
getStartTime() {
|
|
382
641
|
return {
|
|
@@ -389,6 +648,7 @@ shaka.util.TsParser = class {
|
|
|
389
648
|
* Return the audio and video codecs
|
|
390
649
|
*
|
|
391
650
|
* @return {{audio: ?string, video: ?string}}
|
|
651
|
+
* @export
|
|
392
652
|
*/
|
|
393
653
|
getCodecs() {
|
|
394
654
|
return {
|
|
@@ -397,11 +657,169 @@ shaka.util.TsParser = class {
|
|
|
397
657
|
};
|
|
398
658
|
}
|
|
399
659
|
|
|
660
|
+
/**
|
|
661
|
+
* Return the video data
|
|
662
|
+
*
|
|
663
|
+
* @return {!Array.<shaka.extern.VideoNalu>}
|
|
664
|
+
* @export
|
|
665
|
+
*/
|
|
666
|
+
getVideoNalus() {
|
|
667
|
+
const Uint8ArrayUtils = shaka.util.Uint8ArrayUtils;
|
|
668
|
+
let nalus = [];
|
|
669
|
+
let prevVideoData = new Uint8Array(0);
|
|
670
|
+
// parsePES_() only works if the data begins on a PES boundary.
|
|
671
|
+
// Try the last data blob first, and if it doesn't begin on a
|
|
672
|
+
// PES boundary, prepend the previous blob and try again.
|
|
673
|
+
// This way, a successful parse will always begin and end on
|
|
674
|
+
// the correct boundary, and no data will be skipped.
|
|
675
|
+
for (let i = this.videoData_.length - 1; i >= 0; i--) {
|
|
676
|
+
const data = this.videoData_[i];
|
|
677
|
+
goog.asserts.assert(data, 'We should have a data');
|
|
678
|
+
const videoData = Uint8ArrayUtils.concat(data, prevVideoData);
|
|
679
|
+
const pes = this.parsePES_(videoData);
|
|
680
|
+
if (pes) {
|
|
681
|
+
if (this.videoCodec_ == 'avc') {
|
|
682
|
+
nalus = nalus.concat(this.parseAvcNalus(pes));
|
|
683
|
+
}
|
|
684
|
+
prevVideoData = new Uint8Array(0);
|
|
685
|
+
} else {
|
|
686
|
+
prevVideoData = videoData;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
// We need to invert the array to return it in the correct order.
|
|
690
|
+
return nalus.reverse();
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Return the video resolution
|
|
695
|
+
*
|
|
696
|
+
* @return {{height: ?string, width: ?string}}
|
|
697
|
+
* @export
|
|
698
|
+
*/
|
|
699
|
+
getVideoResolution() {
|
|
700
|
+
const TsParser = shaka.util.TsParser;
|
|
701
|
+
const resolution = {
|
|
702
|
+
height: null,
|
|
703
|
+
width: null,
|
|
704
|
+
};
|
|
705
|
+
const videoNalus = this.getVideoNalus();
|
|
706
|
+
if (!videoNalus.length) {
|
|
707
|
+
return resolution;
|
|
708
|
+
}
|
|
709
|
+
const spsNalu = videoNalus.find((nalu) => {
|
|
710
|
+
return nalu.type == TsParser.H264_NALU_TYPE_SPS_;
|
|
711
|
+
});
|
|
712
|
+
if (!spsNalu) {
|
|
713
|
+
return resolution;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
const expGolombDecoder = new shaka.util.ExpGolomb(spsNalu.data);
|
|
717
|
+
// profile_idc
|
|
718
|
+
const profileIdc = expGolombDecoder.readUnsignedByte();
|
|
719
|
+
// constraint_set[0-5]_flag
|
|
720
|
+
expGolombDecoder.readUnsignedByte();
|
|
721
|
+
// level_idc u(8)
|
|
722
|
+
expGolombDecoder.readUnsignedByte();
|
|
723
|
+
// seq_parameter_set_id
|
|
724
|
+
expGolombDecoder.skipExpGolomb();
|
|
725
|
+
|
|
726
|
+
// some profiles have more optional data we don't need
|
|
727
|
+
if (TsParser.PROFILES_WITH_OPTIONAL_SPS_DATA_.includes(profileIdc)) {
|
|
728
|
+
const chromaFormatIdc = expGolombDecoder.readUnsignedExpGolomb();
|
|
729
|
+
if (chromaFormatIdc === 3) {
|
|
730
|
+
// separate_colour_plane_flag
|
|
731
|
+
expGolombDecoder.skipBits(1);
|
|
732
|
+
}
|
|
733
|
+
// bit_depth_luma_minus8
|
|
734
|
+
expGolombDecoder.skipExpGolomb();
|
|
735
|
+
// bit_depth_chroma_minus8
|
|
736
|
+
expGolombDecoder.skipExpGolomb();
|
|
737
|
+
// qpprime_y_zero_transform_bypass_flag
|
|
738
|
+
expGolombDecoder.skipBits(1);
|
|
739
|
+
// seq_scaling_matrix_present_flag
|
|
740
|
+
if (expGolombDecoder.readBoolean()) {
|
|
741
|
+
const scalingListCount = (chromaFormatIdc !== 3) ? 8 : 12;
|
|
742
|
+
for (let i = 0; i < scalingListCount; i++) {
|
|
743
|
+
// seq_scaling_list_present_flag[ i ]
|
|
744
|
+
if (expGolombDecoder.readBoolean()) {
|
|
745
|
+
if (i < 6) {
|
|
746
|
+
expGolombDecoder.skipScalingList(16);
|
|
747
|
+
} else {
|
|
748
|
+
expGolombDecoder.skipScalingList(64);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
// log2_max_frame_num_minus4
|
|
756
|
+
expGolombDecoder.skipExpGolomb();
|
|
757
|
+
const picOrderCntType = expGolombDecoder.readUnsignedExpGolomb();
|
|
758
|
+
|
|
759
|
+
if (picOrderCntType === 0) {
|
|
760
|
+
// log2_max_pic_order_cnt_lsb_minus4
|
|
761
|
+
expGolombDecoder.readUnsignedExpGolomb();
|
|
762
|
+
} else if (picOrderCntType === 1) {
|
|
763
|
+
// delta_pic_order_always_zero_flag
|
|
764
|
+
expGolombDecoder.skipBits(1);
|
|
765
|
+
// offset_for_non_ref_pic
|
|
766
|
+
expGolombDecoder.skipExpGolomb();
|
|
767
|
+
// offset_for_top_to_bottom_field
|
|
768
|
+
expGolombDecoder.skipExpGolomb();
|
|
769
|
+
const numRefFramesInPicOrderCntCycle =
|
|
770
|
+
expGolombDecoder.readUnsignedExpGolomb();
|
|
771
|
+
for (let i = 0; i < numRefFramesInPicOrderCntCycle; i++) {
|
|
772
|
+
// offset_for_ref_frame[ i ]
|
|
773
|
+
expGolombDecoder.skipExpGolomb();
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// max_num_ref_frames
|
|
778
|
+
expGolombDecoder.skipExpGolomb();
|
|
779
|
+
// gaps_in_frame_num_value_allowed_flag
|
|
780
|
+
expGolombDecoder.skipBits(1);
|
|
781
|
+
|
|
782
|
+
const picWidthInMbsMinus1 =
|
|
783
|
+
expGolombDecoder.readUnsignedExpGolomb();
|
|
784
|
+
const picHeightInMapUnitsMinus1 =
|
|
785
|
+
expGolombDecoder.readUnsignedExpGolomb();
|
|
786
|
+
|
|
787
|
+
const frameMbsOnlyFlag = expGolombDecoder.readBits(1);
|
|
788
|
+
if (frameMbsOnlyFlag === 0) {
|
|
789
|
+
// mb_adaptive_frame_field_flag
|
|
790
|
+
expGolombDecoder.skipBits(1);
|
|
791
|
+
}
|
|
792
|
+
// direct_8x8_inference_flag
|
|
793
|
+
expGolombDecoder.skipBits(1);
|
|
794
|
+
|
|
795
|
+
let frameCropLeftOffset = 0;
|
|
796
|
+
let frameCropRightOffset = 0;
|
|
797
|
+
let frameCropTopOffset = 0;
|
|
798
|
+
let frameCropBottomOffset = 0;
|
|
799
|
+
|
|
800
|
+
// frame_cropping_flag
|
|
801
|
+
if (expGolombDecoder.readBoolean()) {
|
|
802
|
+
frameCropLeftOffset = expGolombDecoder.readUnsignedExpGolomb();
|
|
803
|
+
frameCropRightOffset = expGolombDecoder.readUnsignedExpGolomb();
|
|
804
|
+
frameCropTopOffset = expGolombDecoder.readUnsignedExpGolomb();
|
|
805
|
+
frameCropBottomOffset = expGolombDecoder.readUnsignedExpGolomb();
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
resolution.height = String(((2 - frameMbsOnlyFlag) *
|
|
809
|
+
(picHeightInMapUnitsMinus1 + 1) * 16) - (frameCropTopOffset * 2) -
|
|
810
|
+
(frameCropBottomOffset * 2));
|
|
811
|
+
resolution.width = String(((picWidthInMbsMinus1 + 1) * 16) -
|
|
812
|
+
frameCropLeftOffset * 2 - frameCropRightOffset * 2);
|
|
813
|
+
|
|
814
|
+
return resolution;
|
|
815
|
+
}
|
|
816
|
+
|
|
400
817
|
/**
|
|
401
818
|
* Check if the passed data corresponds to an MPEG2-TS
|
|
402
819
|
*
|
|
403
820
|
* @param {Uint8Array} data
|
|
404
821
|
* @return {boolean}
|
|
822
|
+
* @export
|
|
405
823
|
*/
|
|
406
824
|
static probe(data) {
|
|
407
825
|
const syncOffset = shaka.util.TsParser.syncOffset(data);
|
|
@@ -421,6 +839,7 @@ shaka.util.TsParser = class {
|
|
|
421
839
|
*
|
|
422
840
|
* @param {Uint8Array} data
|
|
423
841
|
* @return {number}
|
|
842
|
+
* @export
|
|
424
843
|
*/
|
|
425
844
|
static syncOffset(data) {
|
|
426
845
|
const packetLength = shaka.util.TsParser.PacketLength_;
|
|
@@ -430,9 +849,9 @@ shaka.util.TsParser = class {
|
|
|
430
849
|
while (i < scanwindow) {
|
|
431
850
|
// a TS fragment should contain at least 3 TS packets, a PAT, a PMT, and
|
|
432
851
|
// one PID, each starting with 0x47
|
|
433
|
-
if (data[i]
|
|
434
|
-
data[i + packetLength]
|
|
435
|
-
data[i + 2 * packetLength]
|
|
852
|
+
if (data[i] == 0x47 &&
|
|
853
|
+
data[i + packetLength] == 0x47 &&
|
|
854
|
+
data[i + 2 * packetLength] == 0x47) {
|
|
436
855
|
return i;
|
|
437
856
|
} else {
|
|
438
857
|
i++;
|
|
@@ -443,6 +862,13 @@ shaka.util.TsParser = class {
|
|
|
443
862
|
};
|
|
444
863
|
|
|
445
864
|
|
|
865
|
+
/**
|
|
866
|
+
* @const {number}
|
|
867
|
+
* @export
|
|
868
|
+
*/
|
|
869
|
+
shaka.util.TsParser.Timescale = 90000;
|
|
870
|
+
|
|
871
|
+
|
|
446
872
|
/**
|
|
447
873
|
* @const {number}
|
|
448
874
|
* @private
|
|
@@ -451,10 +877,24 @@ shaka.util.TsParser.PacketLength_ = 188;
|
|
|
451
877
|
|
|
452
878
|
|
|
453
879
|
/**
|
|
880
|
+
* NALU type for Sequence Parameter Set (SPS) for H.264.
|
|
454
881
|
* @const {number}
|
|
455
882
|
* @private
|
|
456
883
|
*/
|
|
457
|
-
shaka.util.TsParser.
|
|
884
|
+
shaka.util.TsParser.H264_NALU_TYPE_SPS_ = 0x07;
|
|
885
|
+
|
|
886
|
+
|
|
887
|
+
/**
|
|
888
|
+
* Values of profile_idc that indicate additional fields are included in the
|
|
889
|
+
* SPS.
|
|
890
|
+
* see Recommendation ITU-T H.264 (4/2013)
|
|
891
|
+
* 7.3.2.1.1 Sequence parameter set data syntax
|
|
892
|
+
*
|
|
893
|
+
* @const {!Array.<number>}
|
|
894
|
+
* @private
|
|
895
|
+
*/
|
|
896
|
+
shaka.util.TsParser.PROFILES_WITH_OPTIONAL_SPS_DATA_ =
|
|
897
|
+
[100, 110, 122, 244, 44, 83, 86, 118, 128, 138, 139, 134];
|
|
458
898
|
|
|
459
899
|
|
|
460
900
|
/**
|
|
@@ -480,20 +920,3 @@ shaka.util.TsParser.Timescale_ = 90000;
|
|
|
480
920
|
*/
|
|
481
921
|
shaka.util.TsParser.PMT;
|
|
482
922
|
|
|
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
|
-
|