shaka-player 3.3.2 → 4.0.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/.csslintrc +11 -1
- package/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- package/.github/pull_request_template.md +6 -34
- package/.github/workflows/build-and-test.yaml +129 -0
- package/.github/workflows/custom-actions/prep-for-appspot/action.yaml +56 -0
- package/.github/workflows/custom-actions/set-commit-status/action.yaml +41 -0
- package/.github/workflows/demo-version-index.yaml +37 -0
- package/.github/workflows/nightly-demo.yaml +42 -0
- package/.github/workflows/release-please.yaml +168 -0
- package/.github/workflows/safari-homedir-launcher.sh +18 -0
- package/.github/workflows/selenium-lab-tests.yaml +92 -0
- package/.github/workflows/sync-labels.yaml +33 -0
- package/.github/workflows/update-issues.yaml +29 -0
- package/.github/workflows/validate-pr-title.yaml +35 -0
- package/AUTHORS +3 -0
- package/CHANGELOG.md +1866 -1675
- package/CONTRIBUTING.md +2 -2
- package/CONTRIBUTORS +3 -0
- package/README.md +16 -13
- package/app-engine/README.md +9 -0
- package/app-engine/demo-version-index/README.md +14 -0
- package/app-engine/demo-version-index/app.yaml +28 -0
- package/app-engine/demo-version-index/generate.py +164 -0
- package/app-engine/demo-version-index/main.py +11 -0
- package/app-engine/demo-version-index/requirements.txt +5 -0
- package/app-engine/demo-version-index/templates/index.html +114 -0
- package/app-engine/shaka-player-demo/README.md +18 -0
- package/app-engine/shaka-player-demo/app.yaml +61 -0
- package/app-engine/shaka-player-demo/main.py +95 -0
- package/app-engine/shaka-player-demo/posters/10yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/10yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/1yo.jpg +0 -0
- package/app-engine/shaka-player-demo/posters/2yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/2yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/3yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/3yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/4yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/4yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/5yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/5yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/6yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/6yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/7yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/7yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/8yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/8yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/9yo.png +0 -0
- package/app-engine/shaka-player-demo/posters/9yo.xcf +0 -0
- package/app-engine/shaka-player-demo/posters/audioOnly.gif +0 -0
- package/app-engine/shaka-player-demo/posters/audioRickRoll.gif +0 -0
- package/app-engine/shaka-player-demo/posters/colorbars.gif +0 -0
- package/app-engine/shaka-player-demo/posters/fireworks.jpg +0 -0
- package/app-engine/shaka-player-demo/posters/party-hat.png +0 -0
- package/app-engine/shaka-player-demo/posters/sources.txt +46 -0
- package/app-engine/shaka-player-demo/posters/standard.png +0 -0
- package/app-engine/shaka-player-demo/posters/trek.jpg +0 -0
- package/app-engine/shaka-player-demo/posters/valentines.png +0 -0
- package/app-engine/shaka-player-demo/posters/zombie.jpg +0 -0
- package/app-engine/shaka-player-demo/posters.py +110 -0
- package/app-engine/shaka-player-demo/requirements.txt +5 -0
- package/app-engine/shaka-player-demo/time.txt +1 -0
- package/build/README.md +3 -3
- package/build/checkversion.py +1 -1
- package/build/compiler.py +1 -1
- package/build/conformance.textproto +13 -0
- package/build/docker/Dockerfile +20 -0
- package/build/docker/docker-compose.yml +10 -0
- package/build/gendeps.py +18 -15
- package/build/shaka-lab.yaml +161 -0
- package/build/shakaBuildHelpers.py +4 -29
- package/build/test.py +94 -29
- package/build/types/core +0 -1
- package/build/types/polyfill +1 -3
- package/build/wrapper.template.js +2 -2
- package/demo/TengwarTelcontar.woff2 +0 -0
- package/demo/asset_card.js +1 -2
- package/demo/cast_receiver/index.html +1 -1
- package/demo/cast_receiver/receiver_app.css +14 -14
- package/demo/common/asset.js +17 -1
- package/demo/common/assets.js +31 -0
- package/demo/common/message_ids.js +6 -3
- package/demo/config.js +10 -12
- package/demo/custom.js +39 -1
- package/demo/customWarning.txt +2 -2
- package/demo/demo.less +29 -18
- package/demo/demo_uncompiled.js +1 -13
- package/demo/demo_utils.js +0 -1
- package/demo/index.html +1 -1
- package/demo/locales/en.json +6 -3
- package/demo/locales/source.json +22 -10
- package/demo/main.js +12 -9
- package/demo/search.js +2 -1
- package/dist/controls.css +3 -3
- package/dist/controls.css.map +1 -1
- package/dist/demo.compiled.debug.js +236 -232
- package/dist/demo.compiled.debug.map +4 -4
- package/dist/demo.compiled.js +236 -232
- package/dist/demo.compiled.map +4 -4
- package/dist/demo.css +1 -1
- package/dist/demo.css.map +1 -1
- package/dist/deps.js +229 -226
- package/dist/locales.js +34 -32
- package/dist/receiver.compiled.debug.js +75 -73
- package/dist/receiver.compiled.debug.map +4 -4
- package/dist/receiver.compiled.js +75 -73
- package/dist/receiver.compiled.map +4 -4
- package/dist/shaka-player.compiled.d.ts +321 -314
- package/dist/shaka-player.compiled.debug.d.ts +321 -314
- package/dist/shaka-player.compiled.debug.externs.js +140 -129
- package/dist/shaka-player.compiled.debug.js +527 -592
- package/dist/shaka-player.compiled.debug.map +4 -4
- package/dist/shaka-player.compiled.externs.js +140 -129
- package/dist/shaka-player.compiled.js +836 -860
- package/dist/shaka-player.compiled.map +4 -4
- package/dist/shaka-player.ui.d.ts +367 -358
- package/dist/shaka-player.ui.debug.d.ts +367 -358
- package/dist/shaka-player.ui.debug.externs.js +148 -129
- package/dist/shaka-player.ui.debug.js +586 -649
- package/dist/shaka-player.ui.debug.map +4 -4
- package/dist/shaka-player.ui.externs.js +148 -129
- package/dist/shaka-player.ui.js +1008 -1028
- package/dist/shaka-player.ui.map +4 -4
- package/docs/design/REDESIGN.md +33 -33
- package/docs/design/bg-fetch.md +2 -2
- package/docs/design/codec_preferences.md +1 -1
- package/docs/design/dash-audio-channels.md +3 -3
- package/docs/design/dash-manifests.md +1 -1
- package/docs/design/gap-jumping.md +3 -3
- package/docs/design/preload.md +2 -2
- package/docs/tutorials/config.md +0 -2
- package/docs/tutorials/drm-config.md +5 -0
- package/docs/tutorials/fairplay.md +7 -22
- package/docs/tutorials/faq.md +8 -19
- package/docs/tutorials/index.json +3 -8
- package/docs/tutorials/plugins.md +4 -6
- package/docs/tutorials/selenium-grid-config.md +122 -0
- package/docs/tutorials/upgrade.md +83 -11
- package/docs/tutorials/welcome.md +10 -2
- package/externs/cmcd.js +1 -1
- package/externs/polyfill.js +15 -0
- package/externs/shaka/manifest.js +5 -1
- package/externs/shaka/net.js +12 -0
- package/externs/shaka/offline.js +5 -1
- package/externs/shaka/player.js +39 -32
- package/externs/shaka/text.js +12 -12
- package/externs/sourcebuffer.js +15 -0
- package/karma.conf.js +137 -30
- package/lib/abr/simple_abr_manager.js +12 -6
- package/lib/ads/client_side_ad.js +13 -2
- package/lib/ads/client_side_ad_manager.js +22 -4
- package/lib/cast/cast_proxy.js +3 -4
- package/lib/cast/cast_utils.js +0 -1
- package/lib/cea/cea608_data_channel.js +2 -2
- package/lib/cea/cea708_service.js +5 -4
- package/lib/cea/mp4_cea_parser.js +11 -5
- package/lib/cea/sei_processor.js +6 -3
- package/lib/dash/content_protection.js +85 -5
- package/lib/dash/dash_parser.js +10 -12
- package/lib/dash/mpd_utils.js +4 -5
- package/lib/dash/segment_list.js +1 -2
- package/lib/dash/segment_template.js +3 -3
- package/lib/hls/hls_parser.js +386 -749
- package/lib/hls/manifest_text_parser.js +5 -6
- package/lib/media/adaptation_set.js +1 -2
- package/lib/media/content_workarounds.js +2 -2
- package/lib/media/drm_engine.js +105 -55
- package/lib/media/gap_jumping_controller.js +10 -45
- package/lib/media/media_source_engine.js +90 -17
- package/lib/media/mp4_segment_index_parser.js +1 -4
- package/lib/media/playhead.js +4 -7
- package/lib/media/presentation_timeline.js +19 -10
- package/lib/media/segment_index.js +13 -46
- package/lib/media/segment_reference.js +47 -1
- package/lib/media/streaming_engine.js +35 -17
- package/lib/media/time_ranges_utils.js +5 -12
- package/lib/media/video_wrapper.js +1 -1
- package/lib/net/networking_engine.js +4 -1
- 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 +104 -136
- package/lib/player.js +50 -216
- package/lib/polyfill/all.js +2 -3
- package/lib/polyfill/encryption_scheme.js +1 -1
- package/lib/polyfill/media_capabilities.js +15 -9
- package/lib/polyfill/mediasource.js +0 -28
- package/lib/polyfill/patchedmediakeys_nop.js +2 -0
- package/lib/polyfill/patchedmediakeys_webkit.js +2 -0
- package/lib/polyfill/symbol.js +46 -0
- package/lib/text/cue.js +1 -7
- package/lib/text/lrc_text_parser.js +8 -0
- package/lib/text/mp4_ttml_parser.js +8 -0
- package/lib/text/mp4_vtt_parser.js +8 -0
- package/lib/text/sbv_text_parser.js +8 -0
- package/lib/text/simple_text_displayer.js +3 -8
- package/lib/text/srt_text_parser.js +8 -0
- package/lib/text/ssa_text_parser.js +8 -0
- package/lib/text/text_engine.js +19 -3
- package/lib/text/ttml_text_parser.js +16 -5
- package/lib/text/ui_text_displayer.js +2 -8
- package/lib/text/vtt_text_parser.js +24 -2
- package/lib/text/web_vtt_generator.js +1 -7
- package/lib/util/buffer_utils.js +1 -3
- package/lib/util/ebml_parser.js +3 -3
- package/lib/util/error.js +10 -14
- package/lib/util/fairplay_utils.js +109 -0
- package/lib/util/functional.js +0 -42
- package/lib/util/iterables.js +0 -46
- package/lib/util/mime_utils.js +2 -0
- package/lib/util/mp4_box_parsers.js +1 -4
- package/lib/util/mp4_parser.js +5 -7
- package/lib/util/periods.js +10 -11
- package/lib/util/platform.js +48 -3
- package/lib/util/player_configuration.js +12 -6
- package/lib/util/pssh.js +24 -8
- package/lib/util/stream_utils.js +96 -25
- package/lib/util/string_utils.js +3 -5
- package/lib/util/uint8array_utils.js +3 -21
- package/lib/util/xml_utils.js +16 -8
- package/package.json +61 -36
- package/roadmap.md +27 -27
- package/shaka-player.uncompiled.js +1 -3
- package/test/abr/simple_abr_manager_unit.js +3 -8
- package/test/ads/ad_manager_unit.js +0 -6
- package/test/cast/cast_proxy_unit.js +0 -8
- package/test/cast/cast_receiver_integration.js +1 -18
- package/test/cast/cast_receiver_unit.js +1 -9
- package/test/cast/cast_sender_unit.js +0 -6
- package/test/cast/cast_utils_unit.js +1 -13
- package/test/cea/cea608_memory_unit.js +0 -5
- package/test/cea/cea708_service_unit.js +0 -7
- package/test/cea/cea708_window_unit.js +0 -5
- package/test/cea/cea_decoder_unit.js +0 -6
- package/test/cea/dtvcc_packet_builder_unit.js +0 -3
- package/test/cea/dtvcc_packet_unit.js +0 -5
- package/test/cea/mp4_cea_parser_unit.js +0 -4
- package/test/dash/dash_parser_content_protection_unit.js +45 -10
- package/test/dash/dash_parser_live_unit.js +2 -15
- package/test/dash/dash_parser_manifest_unit.js +2 -40
- package/test/dash/dash_parser_segment_base_unit.js +1 -8
- package/test/dash/dash_parser_segment_list_unit.js +1 -7
- package/test/dash/dash_parser_segment_template_unit.js +3 -13
- package/test/dash/mpd_utils_unit.js +3 -11
- package/test/demo/demo_unit.js +2 -6
- package/test/deprecate/enforcer_unit.js +0 -4
- package/test/deprecate/version_unit.js +0 -2
- package/test/hls/hls_live_unit.js +101 -234
- package/test/hls/hls_parser_unit.js +517 -447
- package/test/hls/manifest_text_parser_unit.js +0 -10
- package/test/media/adaptation_set_criteria_unit.js +3 -7
- package/test/media/adaptation_set_unit.js +0 -2
- package/test/media/buffering_observer_unit.js +1 -4
- package/test/media/closed_caption_parser_unit.js +0 -3
- package/test/media/drm_engine_integration.js +2 -15
- package/test/media/drm_engine_unit.js +90 -144
- package/test/media/manifest_parser_unit.js +0 -4
- package/test/media/media_source_engine_integration.js +26 -10
- package/test/media/media_source_engine_unit.js +8 -20
- package/test/media/mp4_segment_index_parser_unit.js +0 -4
- package/test/media/play_rate_controller_unit.js +0 -4
- package/test/media/playhead_unit.js +35 -207
- package/test/media/presentation_timeline_unit.js +4 -7
- package/test/media/quality_observer_unit.js +0 -4
- package/test/media/region_observer_unit.js +1 -6
- package/test/media/region_timeline_unit.js +0 -3
- package/test/media/segment_index_unit.js +15 -31
- package/test/media/segment_reference_unit.js +0 -3
- package/test/media/stall_detector_unit.js +0 -5
- package/test/media/streaming_engine_integration.js +13 -75
- package/test/media/streaming_engine_unit.js +14 -37
- package/test/media/time_ranges_utils_unit.js +0 -7
- package/test/media/transmuxer_integration.js +0 -6
- package/test/media/webm_segment_index_parser_unit.js +0 -4
- package/test/net/data_uri_plugin_unit.js +0 -7
- package/test/net/http_plugin_unit.js +0 -9
- package/test/net/networking_engine_unit.js +0 -11
- package/test/offline/download_progress_estimator_unit.js +0 -2
- package/test/offline/indexeddb_storage_unit.js +0 -6
- package/test/offline/manifest_convert_unit.js +34 -12
- package/test/offline/offline_integration.js +1 -10
- package/test/offline/offline_manifest_parser_unit.js +1 -6
- package/test/offline/offline_scheme_unit.js +0 -8
- package/test/offline/offline_uri_unit.js +0 -2
- package/test/offline/storage_compatibility_unit.js +1 -14
- package/test/offline/storage_integration.js +6 -31
- package/test/player_external.js +1 -15
- package/test/player_integration.js +38 -28
- package/test/player_load_graph_integration.js +1 -6
- package/test/player_src_equals_external.js +3 -9
- package/test/player_src_equals_integration.js +0 -7
- package/test/player_unit.js +78 -37
- package/test/routing/walker_unit.js +0 -8
- package/test/test/assets/large_file.mpd +1 -1
- package/test/test/boot.js +75 -22
- package/test/test/externs/jasmine.js +2 -2
- package/test/test/externs/karma.js +4 -0
- package/test/test/namespace.js +10 -0
- package/test/test/util/canned_idb.js +0 -8
- package/test/test/util/cea_utils.js +0 -6
- package/test/test/util/dash_parser_util.js +0 -13
- package/test/test/util/fake_ad.js +0 -3
- package/test/test/util/fake_ad_manager.js +0 -9
- package/test/test/util/fake_demo_main.js +0 -5
- package/test/test/util/fake_drm_engine.js +0 -6
- package/test/test/util/fake_media_source_engine.js +11 -11
- package/test/test/util/fake_networking_engine.js +0 -5
- package/test/test/util/fake_text_displayer.js +0 -5
- package/test/test/util/indexeddb_utils.js +1 -10
- package/test/test/util/jasmine_fetch.js +0 -1
- package/test/test/util/loader.js +0 -18
- package/test/test/util/manifest_generator.js +12 -15
- package/test/test/util/manifest_parser_util.js +4 -7
- package/test/test/util/offline_utils.js +1 -5
- package/test/test/util/simple_fakes.js +9 -26
- package/test/test/util/stream_generator.js +0 -14
- package/test/test/util/streaming_engine_util.js +1 -15
- package/test/test/util/test_scheme.js +25 -20
- package/test/test/util/ttml_utils.js +0 -2
- package/test/test/util/ui_utils.js +0 -9
- package/test/test/util/util.js +9 -23
- package/test/test/util/waiter.js +84 -43
- package/test/text/cue_integration.js +2 -6
- package/test/text/lrc_text_parser_unit.js +6 -11
- package/test/text/mp4_ttml_parser_unit.js +6 -10
- package/test/text/mp4_vtt_parser_unit.js +7 -12
- package/test/text/sbv_text_parser_unit.js +5 -10
- package/test/text/simple_text_displayer_unit.js +1 -8
- package/test/text/srt_text_parser_unit.js +5 -10
- package/test/text/ssa_text_parser_unit.js +17 -34
- package/test/text/text_engine_unit.js +47 -12
- package/test/text/text_track_integration.js +0 -2
- package/test/text/ttml_text_parser_unit.js +79 -88
- package/test/text/ui_text_displayer_unit.js +44 -41
- package/test/text/vtt_text_parser_unit.js +55 -66
- package/test/text/web_vtt_generator_unit.js +0 -3
- package/test/ui/ad_ui_unit.js +0 -11
- package/test/ui/localization_unit.js +0 -3
- package/test/ui/text_displayer_layout_unit.js +1 -12
- package/test/ui/ui_customization_unit.js +0 -6
- package/test/ui/ui_integration.js +0 -32
- package/test/ui/ui_unit.js +28 -17
- package/test/util/abortable_operation_unit.js +4 -9
- package/test/util/array_utils_unit.js +0 -2
- package/test/util/buffer_utils_unit.js +0 -2
- package/test/util/cmcd_manager_unit.js +3 -3
- package/test/util/data_view_reader_unit.js +0 -4
- package/test/util/ebml_parser_unit.js +0 -4
- package/test/util/event_manager_unit.js +0 -3
- package/test/util/fake_event_target_unit.js +0 -5
- package/test/util/iterables_unit.js +0 -64
- package/test/util/language_utils_unit.js +0 -3
- package/test/util/manifest_parser_utils_unit.js +0 -2
- package/test/util/mp4_box_parsers_unit.js +0 -5
- package/test/util/mp4_parser_unit.js +0 -4
- package/test/util/multi_map_unit.js +0 -3
- package/test/util/object_utils_unit.js +0 -2
- package/test/util/periods_unit.js +14 -7
- package/test/util/pssh_unit.js +0 -5
- package/test/util/state_history_unit.js +0 -2
- package/test/util/stream_utils_unit.js +26 -15
- package/test/util/string_utils_unit.js +0 -6
- package/test/util/text_parser_unit.js +0 -2
- package/test/util/xml_utils_unit.js +0 -4
- package/ui/controls.js +65 -40
- package/ui/fullscreen_button.js +26 -6
- package/ui/less/ad_controls.less +6 -6
- package/ui/less/buttons.less +6 -6
- package/ui/less/containers.less +10 -12
- package/ui/less/overflow_menu.less +4 -4
- package/ui/less/range_elements.less +7 -2
- package/ui/less/tooltip.less +4 -4
- package/ui/locales/en.json +1 -0
- package/ui/locales/sjn-translations.yaml +257 -0
- package/ui/locales/sjn.json +42 -0
- package/ui/locales/source.json +5 -0
- package/ui/resolution_selection.js +31 -33
- package/ui/seek_bar.js +2 -1
- package/ui/ui.js +0 -17
- package/.github/workflows/build_and_test.yaml +0 -73
- package/.github/workflows/release.yaml +0 -53
- package/docs/tutorials/upgrade-v2-5.md +0 -441
- package/docs/tutorials/upgrade-v3.md +0 -38
- package/externs/svgelement.js +0 -18
- package/externs/webcrypto.js +0 -18
- package/lib/polyfill/mathround.js +0 -49
- package/lib/polyfill/patchedmediakeys_apple.js +0 -744
- package/lib/polyfill/patchedmediakeys_ms.js +0 -698
- package/lib/util/mutex.js +0 -52
- package/test/util/functional_unit.js +0 -82
|
@@ -4,22 +4,8 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
goog.require('goog.asserts');
|
|
8
|
-
goog.require('shaka.hls.HlsParser');
|
|
9
|
-
goog.require('shaka.log');
|
|
10
|
-
goog.require('shaka.net.NetworkingEngine');
|
|
11
|
-
goog.require('shaka.test.FakeNetworkingEngine');
|
|
12
|
-
goog.require('shaka.test.ManifestGenerator');
|
|
13
|
-
goog.require('shaka.test.ManifestParser');
|
|
14
|
-
goog.require('shaka.test.Util');
|
|
15
|
-
goog.require('shaka.util.Error');
|
|
16
|
-
goog.require('shaka.util.ManifestParserUtils');
|
|
17
|
-
goog.require('shaka.util.PlayerConfiguration');
|
|
18
|
-
goog.require('shaka.util.Uint8ArrayUtils');
|
|
19
|
-
|
|
20
7
|
describe('HlsParser', () => {
|
|
21
8
|
const ContentType = shaka.util.ManifestParserUtils.ContentType;
|
|
22
|
-
const ManifestParser = shaka.test.ManifestParser;
|
|
23
9
|
const TextStreamKind = shaka.util.ManifestParserUtils.TextStreamKind;
|
|
24
10
|
const Util = shaka.test.Util;
|
|
25
11
|
const originalAlwaysWarn = shaka.log.alwaysWarn;
|
|
@@ -169,6 +155,7 @@ describe('HlsParser', () => {
|
|
|
169
155
|
].join('');
|
|
170
156
|
|
|
171
157
|
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
158
|
+
manifest.sequenceMode = true;
|
|
172
159
|
manifest.anyTimeline();
|
|
173
160
|
manifest.addPartialVariant((variant) => {
|
|
174
161
|
variant.language = 'en';
|
|
@@ -243,6 +230,7 @@ describe('HlsParser', () => {
|
|
|
243
230
|
].join('');
|
|
244
231
|
|
|
245
232
|
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
233
|
+
manifest.sequenceMode = true;
|
|
246
234
|
manifest.anyTimeline();
|
|
247
235
|
manifest.addPartialVariant((variant) => {
|
|
248
236
|
variant.language = 'en';
|
|
@@ -313,6 +301,7 @@ describe('HlsParser', () => {
|
|
|
313
301
|
stream.size(960, 540);
|
|
314
302
|
});
|
|
315
303
|
});
|
|
304
|
+
manifest.sequenceMode = true;
|
|
316
305
|
});
|
|
317
306
|
|
|
318
307
|
fakeNetEngine
|
|
@@ -349,6 +338,7 @@ describe('HlsParser', () => {
|
|
|
349
338
|
stream.mime('video/mp4', 'avc1.4d001e');
|
|
350
339
|
});
|
|
351
340
|
});
|
|
341
|
+
manifest.sequenceMode = true;
|
|
352
342
|
});
|
|
353
343
|
|
|
354
344
|
await testHlsParser(master, media, manifest);
|
|
@@ -378,6 +368,7 @@ describe('HlsParser', () => {
|
|
|
378
368
|
stream.mime('video/mp4', 'avc1');
|
|
379
369
|
});
|
|
380
370
|
});
|
|
371
|
+
manifest.sequenceMode = true;
|
|
381
372
|
});
|
|
382
373
|
|
|
383
374
|
await testHlsParser(master, media, manifest);
|
|
@@ -406,6 +397,7 @@ describe('HlsParser', () => {
|
|
|
406
397
|
stream.mime('video/mp4', 'avc1');
|
|
407
398
|
});
|
|
408
399
|
});
|
|
400
|
+
manifest.sequenceMode = true;
|
|
409
401
|
});
|
|
410
402
|
|
|
411
403
|
await testHlsParser(master, media, manifest);
|
|
@@ -437,6 +429,7 @@ describe('HlsParser', () => {
|
|
|
437
429
|
stream.mime('video/mp4', 'avc1');
|
|
438
430
|
});
|
|
439
431
|
});
|
|
432
|
+
manifest.sequenceMode = true;
|
|
440
433
|
});
|
|
441
434
|
|
|
442
435
|
await testHlsParser(master, media, manifest);
|
|
@@ -465,6 +458,7 @@ describe('HlsParser', () => {
|
|
|
465
458
|
stream.mime('audio/mp4', 'mp4a');
|
|
466
459
|
});
|
|
467
460
|
});
|
|
461
|
+
manifest.sequenceMode = true;
|
|
468
462
|
});
|
|
469
463
|
|
|
470
464
|
await testHlsParser(master, media, manifest);
|
|
@@ -499,6 +493,7 @@ describe('HlsParser', () => {
|
|
|
499
493
|
stream.mime('audio/mp4', 'mp4a');
|
|
500
494
|
});
|
|
501
495
|
});
|
|
496
|
+
manifest.sequenceMode = true;
|
|
502
497
|
});
|
|
503
498
|
|
|
504
499
|
await testHlsParser(master, media, manifest);
|
|
@@ -533,6 +528,35 @@ describe('HlsParser', () => {
|
|
|
533
528
|
stream.mime('audio/mp4', '');
|
|
534
529
|
});
|
|
535
530
|
});
|
|
531
|
+
manifest.sequenceMode = true;
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
await testHlsParser(master, media, manifest);
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
it('accepts containerless streams', async () => {
|
|
538
|
+
const master = [
|
|
539
|
+
'#EXTM3U\n',
|
|
540
|
+
'#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=41457,CODECS="mp4a.40.2"\n',
|
|
541
|
+
'audio\n',
|
|
542
|
+
].join('');
|
|
543
|
+
|
|
544
|
+
const media = [
|
|
545
|
+
'#EXTM3U\n',
|
|
546
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
547
|
+
'#EXTINF:5,\n',
|
|
548
|
+
'#EXT-X-BYTERANGE:121090@616\n',
|
|
549
|
+
'main.aac',
|
|
550
|
+
].join('');
|
|
551
|
+
|
|
552
|
+
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
553
|
+
manifest.anyTimeline();
|
|
554
|
+
manifest.addPartialVariant((variant) => {
|
|
555
|
+
variant.addPartialStream(ContentType.AUDIO, (stream) => {
|
|
556
|
+
stream.mime('audio/aac', '');
|
|
557
|
+
});
|
|
558
|
+
});
|
|
559
|
+
manifest.sequenceMode = true;
|
|
536
560
|
});
|
|
537
561
|
|
|
538
562
|
await testHlsParser(master, media, manifest);
|
|
@@ -571,6 +595,7 @@ describe('HlsParser', () => {
|
|
|
571
595
|
stream.mime('audio/mp4', 'mp4a');
|
|
572
596
|
});
|
|
573
597
|
});
|
|
598
|
+
manifest.sequenceMode = true;
|
|
574
599
|
});
|
|
575
600
|
|
|
576
601
|
await testHlsParser(master, media, manifest);
|
|
@@ -607,6 +632,7 @@ describe('HlsParser', () => {
|
|
|
607
632
|
stream.mime('audio/mp4', 'mp4a');
|
|
608
633
|
});
|
|
609
634
|
});
|
|
635
|
+
manifest.sequenceMode = true;
|
|
610
636
|
});
|
|
611
637
|
|
|
612
638
|
await testHlsParser(master, media, manifest);
|
|
@@ -637,66 +663,12 @@ describe('HlsParser', () => {
|
|
|
637
663
|
stream.mime('audio/mp4', 'mp4a');
|
|
638
664
|
});
|
|
639
665
|
});
|
|
666
|
+
manifest.sequenceMode = true;
|
|
640
667
|
});
|
|
641
668
|
|
|
642
669
|
await testHlsParser(master, media, manifest);
|
|
643
670
|
});
|
|
644
671
|
|
|
645
|
-
it('sets seek range correctly for non-zero start', async () => {
|
|
646
|
-
const master = [
|
|
647
|
-
'#EXTM3U\n',
|
|
648
|
-
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",',
|
|
649
|
-
'RESOLUTION=960x540,FRAME-RATE=60\n',
|
|
650
|
-
'video',
|
|
651
|
-
].join('');
|
|
652
|
-
|
|
653
|
-
const media = [
|
|
654
|
-
'#EXTM3U\n',
|
|
655
|
-
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
656
|
-
'#EXT-X-MEDIA-SEQUENCE:131\n',
|
|
657
|
-
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
658
|
-
'#EXTINF:5,\n',
|
|
659
|
-
'#EXT-X-BYTERANGE:121090@616\n',
|
|
660
|
-
'main.mp4',
|
|
661
|
-
].join('');
|
|
662
|
-
|
|
663
|
-
segmentData = new Uint8Array([
|
|
664
|
-
0x00, 0x00, 0x00, 0x24, // size (36)
|
|
665
|
-
0x6D, 0x6F, 0x6F, 0x66, // type (moof)
|
|
666
|
-
0x00, 0x00, 0x00, 0x1C, // traf size (28)
|
|
667
|
-
0x74, 0x72, 0x61, 0x66, // type (traf)
|
|
668
|
-
|
|
669
|
-
0x00, 0x00, 0x00, 0x14, // tfdt size (20)
|
|
670
|
-
0x74, 0x66, 0x64, 0x74, // type (tfdt)
|
|
671
|
-
0x01, 0x00, 0x00, 0x00, // version and flags
|
|
672
|
-
|
|
673
|
-
0x00, 0x00, 0x00, 0x00, // baseMediaDecodeTime first 4 bytes (0)
|
|
674
|
-
0x00, 0x0A, 0x00, 0x00, // baseMediaDecodeTime last 4 bytes (655360)
|
|
675
|
-
]);
|
|
676
|
-
|
|
677
|
-
fakeNetEngine
|
|
678
|
-
.setResponseText('test:/master', master)
|
|
679
|
-
.setResponseText('test:/video', media)
|
|
680
|
-
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
681
|
-
.setResponseValue('test:/main.mp4', segmentData);
|
|
682
|
-
|
|
683
|
-
const manifest = await parser.start('test:/master', playerInterface);
|
|
684
|
-
const presentationTimeline = manifest.presentationTimeline;
|
|
685
|
-
const stream = manifest.variants[0].video;
|
|
686
|
-
await stream.createSegmentIndex();
|
|
687
|
-
goog.asserts.assert(stream.segmentIndex != null, 'Null segmentIndex!');
|
|
688
|
-
|
|
689
|
-
const ref = Array.from(stream.segmentIndex)[0];
|
|
690
|
-
expect(ref).not.toBe(null);
|
|
691
|
-
if (ref) {
|
|
692
|
-
expect(ref.startTime).toBe(0);
|
|
693
|
-
// baseMediaDecodeTime (655360) / timescale (1000)
|
|
694
|
-
expect(ref.timestampOffset).toBe(-655.36);
|
|
695
|
-
}
|
|
696
|
-
expect(presentationTimeline.getSeekRangeStart()).toBe(0);
|
|
697
|
-
expect(presentationTimeline.getSeekRangeEnd()).toBe(5);
|
|
698
|
-
});
|
|
699
|
-
|
|
700
672
|
it('parses multiplexed variant', async () => {
|
|
701
673
|
const master = [
|
|
702
674
|
'#EXTM3U\n',
|
|
@@ -721,6 +693,7 @@ describe('HlsParser', () => {
|
|
|
721
693
|
stream.mime('video/mp4', 'avc1,mp4a');
|
|
722
694
|
});
|
|
723
695
|
});
|
|
696
|
+
manifest.sequenceMode = true;
|
|
724
697
|
});
|
|
725
698
|
|
|
726
699
|
await testHlsParser(master, media, manifest);
|
|
@@ -750,6 +723,7 @@ describe('HlsParser', () => {
|
|
|
750
723
|
stream.mime('video/mp4', /** @type {?} */ (jasmine.any(String)));
|
|
751
724
|
});
|
|
752
725
|
});
|
|
726
|
+
manifest.sequenceMode = true;
|
|
753
727
|
});
|
|
754
728
|
|
|
755
729
|
await testHlsParser(master, media, manifest);
|
|
@@ -784,6 +758,7 @@ describe('HlsParser', () => {
|
|
|
784
758
|
stream.mime('audio/mp4', /** @type {?} */ (jasmine.any(String)));
|
|
785
759
|
});
|
|
786
760
|
});
|
|
761
|
+
manifest.sequenceMode = true;
|
|
787
762
|
});
|
|
788
763
|
|
|
789
764
|
await testHlsParser(master, media, manifest);
|
|
@@ -814,6 +789,7 @@ describe('HlsParser', () => {
|
|
|
814
789
|
stream.mime('video/mp4', /** @type {?} */ (jasmine.any(String)));
|
|
815
790
|
});
|
|
816
791
|
});
|
|
792
|
+
manifest.sequenceMode = true;
|
|
817
793
|
});
|
|
818
794
|
|
|
819
795
|
await testHlsParser(master, media, manifest);
|
|
@@ -844,6 +820,7 @@ describe('HlsParser', () => {
|
|
|
844
820
|
stream.mime('audio/mp4', /** @type {?} */ (jasmine.any(String)));
|
|
845
821
|
});
|
|
846
822
|
});
|
|
823
|
+
manifest.sequenceMode = true;
|
|
847
824
|
});
|
|
848
825
|
|
|
849
826
|
await testHlsParser(master, media, manifest);
|
|
@@ -895,6 +872,7 @@ describe('HlsParser', () => {
|
|
|
895
872
|
stream.language = 'fr';
|
|
896
873
|
});
|
|
897
874
|
});
|
|
875
|
+
manifest.sequenceMode = true;
|
|
898
876
|
});
|
|
899
877
|
|
|
900
878
|
await testHlsParser(master, media, manifest);
|
|
@@ -937,6 +915,7 @@ describe('HlsParser', () => {
|
|
|
937
915
|
stream.language = 'fr';
|
|
938
916
|
});
|
|
939
917
|
});
|
|
918
|
+
manifest.sequenceMode = true;
|
|
940
919
|
});
|
|
941
920
|
|
|
942
921
|
await testHlsParser(master, media, manifest);
|
|
@@ -984,63 +963,12 @@ describe('HlsParser', () => {
|
|
|
984
963
|
];
|
|
985
964
|
});
|
|
986
965
|
});
|
|
966
|
+
manifest.sequenceMode = true;
|
|
987
967
|
});
|
|
988
968
|
|
|
989
969
|
await testHlsParser(master, media, manifest);
|
|
990
970
|
});
|
|
991
971
|
|
|
992
|
-
it('fetch the start time for one audio/video stream and reuse for the others',
|
|
993
|
-
async () => {
|
|
994
|
-
const SEGMENT = shaka.net.NetworkingEngine.RequestType.SEGMENT;
|
|
995
|
-
const master = [
|
|
996
|
-
'#EXTM3U\n',
|
|
997
|
-
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",',
|
|
998
|
-
'CHANNELS="2",URI="audio"\n',
|
|
999
|
-
'#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="sub1",LANGUAGE="eng",',
|
|
1000
|
-
'URI="text"\n',
|
|
1001
|
-
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",',
|
|
1002
|
-
'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1"\n',
|
|
1003
|
-
'video\n',
|
|
1004
|
-
].join('');
|
|
1005
|
-
|
|
1006
|
-
const media = [
|
|
1007
|
-
'#EXTM3U\n',
|
|
1008
|
-
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1009
|
-
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
1010
|
-
'#EXTINF:5,\n',
|
|
1011
|
-
'#EXT-X-BYTERANGE:121090@616\n',
|
|
1012
|
-
'main.mp4',
|
|
1013
|
-
].join('');
|
|
1014
|
-
|
|
1015
|
-
const textMedia = [
|
|
1016
|
-
'#EXTM3U\n',
|
|
1017
|
-
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1018
|
-
'#EXTINF:5,\n',
|
|
1019
|
-
'#EXT-X-BYTERANGE:121090@616\n',
|
|
1020
|
-
'main.vtt',
|
|
1021
|
-
].join('');
|
|
1022
|
-
|
|
1023
|
-
fakeNetEngine
|
|
1024
|
-
.setResponseText('test:/master', master)
|
|
1025
|
-
.setResponseText('test:/audio', media)
|
|
1026
|
-
.setResponseText('test:/video', media)
|
|
1027
|
-
.setResponseText('test:/text', textMedia)
|
|
1028
|
-
.setResponseText('test:/main.vtt', vttText)
|
|
1029
|
-
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
1030
|
-
.setResponseValue('test:/main.mp4', segmentData);
|
|
1031
|
-
|
|
1032
|
-
await parser.start('test:/master', playerInterface);
|
|
1033
|
-
// The start time of audio should be fetched first, and then video and
|
|
1034
|
-
// text streams should reuse the start time from audio.
|
|
1035
|
-
// Thus, there should be 2 segment requests, for fetching audio init
|
|
1036
|
-
// and main segments, and not for video and text segments.
|
|
1037
|
-
expect(fakeNetEngine.request.calls.allArgs().filter((args) => {
|
|
1038
|
-
return args[0] == SEGMENT;
|
|
1039
|
-
}).length).toBe(2);
|
|
1040
|
-
fakeNetEngine.expectRequest('test:/init.mp4', SEGMENT);
|
|
1041
|
-
fakeNetEngine.expectRequest('test:/main.mp4', SEGMENT);
|
|
1042
|
-
});
|
|
1043
|
-
|
|
1044
972
|
it('gets mime type from header request', async () => {
|
|
1045
973
|
const master = [
|
|
1046
974
|
'#EXTM3U\n',
|
|
@@ -1065,6 +993,7 @@ describe('HlsParser', () => {
|
|
|
1065
993
|
stream.mime('video/mp4', 'avc1');
|
|
1066
994
|
});
|
|
1067
995
|
});
|
|
996
|
+
manifest.sequenceMode = true;
|
|
1068
997
|
});
|
|
1069
998
|
|
|
1070
999
|
// The extra parameters should be stripped by the parser.
|
|
@@ -1122,6 +1051,7 @@ describe('HlsParser', () => {
|
|
|
1122
1051
|
stream.kind = TextStreamKind.SUBTITLE;
|
|
1123
1052
|
stream.mime('text/vtt', '');
|
|
1124
1053
|
});
|
|
1054
|
+
manifest.sequenceMode = true;
|
|
1125
1055
|
});
|
|
1126
1056
|
|
|
1127
1057
|
fakeNetEngine
|
|
@@ -1191,6 +1121,7 @@ describe('HlsParser', () => {
|
|
|
1191
1121
|
stream.kind = TextStreamKind.SUBTITLE;
|
|
1192
1122
|
stream.mime('text/vtt', '');
|
|
1193
1123
|
});
|
|
1124
|
+
manifest.sequenceMode = true;
|
|
1194
1125
|
});
|
|
1195
1126
|
|
|
1196
1127
|
fakeNetEngine
|
|
@@ -1207,6 +1138,69 @@ describe('HlsParser', () => {
|
|
|
1207
1138
|
expect(actual).toEqual(manifest);
|
|
1208
1139
|
});
|
|
1209
1140
|
|
|
1141
|
+
it('gets mime type of SUBTITLES from header request', async () => {
|
|
1142
|
+
const master = [
|
|
1143
|
+
'#EXTM3U\n',
|
|
1144
|
+
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",',
|
|
1145
|
+
'URI="audio"\n',
|
|
1146
|
+
'#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="sub1",LANGUAGE="eng",',
|
|
1147
|
+
'URI="text"\n',
|
|
1148
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",',
|
|
1149
|
+
'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1",SUBTITLES="sub1"\n',
|
|
1150
|
+
'video\n',
|
|
1151
|
+
].join('');
|
|
1152
|
+
|
|
1153
|
+
const media = [
|
|
1154
|
+
'#EXTM3U\n',
|
|
1155
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1156
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
1157
|
+
'#EXTINF:5,\n',
|
|
1158
|
+
'#EXT-X-BYTERANGE:121090@616\n',
|
|
1159
|
+
'main.mp4',
|
|
1160
|
+
].join('');
|
|
1161
|
+
|
|
1162
|
+
const textMedia = [
|
|
1163
|
+
'#EXTM3U\n',
|
|
1164
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1165
|
+
'#EXTINF:5,\n',
|
|
1166
|
+
'#EXT-X-BYTERANGE:121090@616\n',
|
|
1167
|
+
'main.subs',
|
|
1168
|
+
].join('');
|
|
1169
|
+
|
|
1170
|
+
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
1171
|
+
manifest.anyTimeline();
|
|
1172
|
+
manifest.addPartialVariant((variant) => {
|
|
1173
|
+
variant.addPartialStream(ContentType.VIDEO, (stream) => {
|
|
1174
|
+
stream.mime('video/mp4', 'avc1');
|
|
1175
|
+
});
|
|
1176
|
+
variant.addPartialStream(ContentType.AUDIO, (stream) => {
|
|
1177
|
+
stream.mime('audio/mp4', 'mp4a');
|
|
1178
|
+
});
|
|
1179
|
+
});
|
|
1180
|
+
manifest.addPartialTextStream((stream) => {
|
|
1181
|
+
stream.language = 'en';
|
|
1182
|
+
stream.kind = TextStreamKind.SUBTITLE;
|
|
1183
|
+
stream.mime('application/mp4', '');
|
|
1184
|
+
});
|
|
1185
|
+
manifest.sequenceMode = true;
|
|
1186
|
+
});
|
|
1187
|
+
|
|
1188
|
+
fakeNetEngine
|
|
1189
|
+
.setResponseText('test:/master', master)
|
|
1190
|
+
.setResponseText('test:/audio', media)
|
|
1191
|
+
.setResponseText('test:/video', media)
|
|
1192
|
+
.setResponseText('test:/text', textMedia)
|
|
1193
|
+
.setResponseText('test:/main.subs', vttText)
|
|
1194
|
+
.setHeaders('test:/main.subs', {
|
|
1195
|
+
'content-type': 'application/mp4; foo=bar',
|
|
1196
|
+
})
|
|
1197
|
+
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
1198
|
+
.setResponseValue('test:/main.mp4', segmentData);
|
|
1199
|
+
|
|
1200
|
+
const actual = await parser.start('test:/master', playerInterface);
|
|
1201
|
+
expect(actual).toEqual(manifest);
|
|
1202
|
+
});
|
|
1203
|
+
|
|
1210
1204
|
it('parses manifest with FORCED SUBTITLES', async () => {
|
|
1211
1205
|
const master = [
|
|
1212
1206
|
'#EXTM3U\n',
|
|
@@ -1252,6 +1246,7 @@ describe('HlsParser', () => {
|
|
|
1252
1246
|
stream.kind = TextStreamKind.SUBTITLE;
|
|
1253
1247
|
stream.mime('text/vtt', '');
|
|
1254
1248
|
});
|
|
1249
|
+
manifest.sequenceMode = true;
|
|
1255
1250
|
});
|
|
1256
1251
|
|
|
1257
1252
|
fakeNetEngine
|
|
@@ -1313,6 +1308,7 @@ describe('HlsParser', () => {
|
|
|
1313
1308
|
stream.kind = TextStreamKind.SUBTITLE;
|
|
1314
1309
|
stream.mime('text/vtt', '');
|
|
1315
1310
|
});
|
|
1311
|
+
manifest.sequenceMode = true;
|
|
1316
1312
|
});
|
|
1317
1313
|
|
|
1318
1314
|
fakeNetEngine
|
|
@@ -1491,6 +1487,105 @@ describe('HlsParser', () => {
|
|
|
1491
1487
|
}
|
|
1492
1488
|
});
|
|
1493
1489
|
|
|
1490
|
+
it('parse EXT-X-GAP', async () => {
|
|
1491
|
+
const master = [
|
|
1492
|
+
'#EXTM3U\n',
|
|
1493
|
+
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",',
|
|
1494
|
+
'CHANNELS="2",URI="audio"\n',
|
|
1495
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",',
|
|
1496
|
+
'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1"\n',
|
|
1497
|
+
'video\n',
|
|
1498
|
+
].join('');
|
|
1499
|
+
|
|
1500
|
+
const video = [
|
|
1501
|
+
'#EXTM3U\n',
|
|
1502
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1503
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
1504
|
+
'#EXTINF:5,\n',
|
|
1505
|
+
'main.mp4\n',
|
|
1506
|
+
'#EXTINF:5,\n',
|
|
1507
|
+
'#EXT-X-GAP\n',
|
|
1508
|
+
'main.mp4\n',
|
|
1509
|
+
'#EXTINF:5,\n',
|
|
1510
|
+
'main.mp4\n',
|
|
1511
|
+
].join('');
|
|
1512
|
+
|
|
1513
|
+
const audio = [
|
|
1514
|
+
'#EXTM3U\n',
|
|
1515
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
1516
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
1517
|
+
'#EXTINF:5,\n',
|
|
1518
|
+
'main.mp4\n',
|
|
1519
|
+
'#EXTINF:5,\n',
|
|
1520
|
+
'#EXT-X-GAP\n',
|
|
1521
|
+
'main.mp4\n',
|
|
1522
|
+
'#EXTINF:5,\n',
|
|
1523
|
+
'main.mp4\n',
|
|
1524
|
+
].join('');
|
|
1525
|
+
|
|
1526
|
+
fakeNetEngine
|
|
1527
|
+
.setResponseText('test:/master', master)
|
|
1528
|
+
.setResponseText('test:/audio', audio)
|
|
1529
|
+
.setResponseText('test:/video', video)
|
|
1530
|
+
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
1531
|
+
.setResponseValue('test:/main.mp4', segmentData);
|
|
1532
|
+
|
|
1533
|
+
const actual = await parser.start('test:/master', playerInterface);
|
|
1534
|
+
|
|
1535
|
+
expect(actual.variants.length).toBe(1);
|
|
1536
|
+
|
|
1537
|
+
const variant = actual.variants[0];
|
|
1538
|
+
expect(variant.video).toBeTruthy();
|
|
1539
|
+
expect(variant.audio).toBeTruthy();
|
|
1540
|
+
|
|
1541
|
+
const available = shaka.media.SegmentReference.Status.AVAILABLE;
|
|
1542
|
+
const missing = shaka.media.SegmentReference.Status.MISSING;
|
|
1543
|
+
|
|
1544
|
+
await variant.video.createSegmentIndex();
|
|
1545
|
+
goog.asserts.assert(variant.video.segmentIndex != null,
|
|
1546
|
+
'Null segmentIndex!');
|
|
1547
|
+
|
|
1548
|
+
const firstVideoReference = variant.video.segmentIndex.get(0);
|
|
1549
|
+
const secondVideoReference = variant.video.segmentIndex.get(1);
|
|
1550
|
+
const thirdVideoReference = variant.video.segmentIndex.get(2);
|
|
1551
|
+
|
|
1552
|
+
expect(firstVideoReference).not.toBe(null);
|
|
1553
|
+
expect(secondVideoReference).not.toBe(null);
|
|
1554
|
+
expect(thirdVideoReference).not.toBe(null);
|
|
1555
|
+
|
|
1556
|
+
if (firstVideoReference) {
|
|
1557
|
+
expect(firstVideoReference.getStatus()).toBe(available);
|
|
1558
|
+
}
|
|
1559
|
+
if (secondVideoReference) {
|
|
1560
|
+
expect(secondVideoReference.getStatus()).toBe(missing);
|
|
1561
|
+
}
|
|
1562
|
+
if (thirdVideoReference) {
|
|
1563
|
+
expect(thirdVideoReference.getStatus()).toBe(available);
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
await variant.audio.createSegmentIndex();
|
|
1567
|
+
goog.asserts.assert(variant.audio.segmentIndex != null,
|
|
1568
|
+
'Null segmentIndex!');
|
|
1569
|
+
|
|
1570
|
+
const firstAudioReference = variant.audio.segmentIndex.get(0);
|
|
1571
|
+
const secondAudioReference = variant.audio.segmentIndex.get(1);
|
|
1572
|
+
const thirdAudioReference = variant.audio.segmentIndex.get(2);
|
|
1573
|
+
|
|
1574
|
+
expect(firstAudioReference).not.toBe(null);
|
|
1575
|
+
expect(secondAudioReference).not.toBe(null);
|
|
1576
|
+
expect(thirdAudioReference).not.toBe(null);
|
|
1577
|
+
|
|
1578
|
+
if (firstAudioReference) {
|
|
1579
|
+
expect(firstAudioReference.getStatus()).toBe(available);
|
|
1580
|
+
}
|
|
1581
|
+
if (secondAudioReference) {
|
|
1582
|
+
expect(secondAudioReference.getStatus()).toBe(missing);
|
|
1583
|
+
}
|
|
1584
|
+
if (thirdAudioReference) {
|
|
1585
|
+
expect(thirdAudioReference.getStatus()).toBe(available);
|
|
1586
|
+
}
|
|
1587
|
+
});
|
|
1588
|
+
|
|
1494
1589
|
it('Disable audio does not create audio streams', async () => {
|
|
1495
1590
|
const master = [
|
|
1496
1591
|
'#EXTM3U\n',
|
|
@@ -1817,6 +1912,7 @@ describe('HlsParser', () => {
|
|
|
1817
1912
|
stream.language = 'en';
|
|
1818
1913
|
stream.mime('application/mp4', 'stpp.ttml.im1t');
|
|
1819
1914
|
});
|
|
1915
|
+
manifest.sequenceMode = true;
|
|
1820
1916
|
});
|
|
1821
1917
|
|
|
1822
1918
|
fakeNetEngine
|
|
@@ -1866,6 +1962,7 @@ describe('HlsParser', () => {
|
|
|
1866
1962
|
manifest.addPartialTextStream((stream) => {
|
|
1867
1963
|
stream.mime('text/vtt', 'vtt');
|
|
1868
1964
|
});
|
|
1965
|
+
manifest.sequenceMode = true;
|
|
1869
1966
|
});
|
|
1870
1967
|
|
|
1871
1968
|
fakeNetEngine
|
|
@@ -1908,6 +2005,7 @@ describe('HlsParser', () => {
|
|
|
1908
2005
|
manifest.addPartialTextStream((stream) => {
|
|
1909
2006
|
stream.kind = TextStreamKind.SUBTITLE;
|
|
1910
2007
|
});
|
|
2008
|
+
manifest.sequenceMode = true;
|
|
1911
2009
|
});
|
|
1912
2010
|
|
|
1913
2011
|
fakeNetEngine
|
|
@@ -1922,6 +2020,173 @@ describe('HlsParser', () => {
|
|
|
1922
2020
|
expect(actual).toEqual(manifest);
|
|
1923
2021
|
});
|
|
1924
2022
|
|
|
2023
|
+
describe('produces syncTime', () => {
|
|
2024
|
+
/**
|
|
2025
|
+
* @param {number} startTime
|
|
2026
|
+
* @param {number} endTime
|
|
2027
|
+
* @param {number} syncTime
|
|
2028
|
+
* @return {!shaka.media.SegmentReference}
|
|
2029
|
+
*/
|
|
2030
|
+
function makeReference(startTime, endTime, syncTime) {
|
|
2031
|
+
const initUris = () => ['test:/init.mp4'];
|
|
2032
|
+
const init = new shaka.media.InitSegmentReference(initUris, 0, 615);
|
|
2033
|
+
const uris = () => ['test:/main.mp4'];
|
|
2034
|
+
return new shaka.media.SegmentReference(
|
|
2035
|
+
startTime, endTime, uris, 0, null, init, 0, 0, Infinity,
|
|
2036
|
+
[], undefined, undefined, syncTime);
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
/**
|
|
2040
|
+
* @param {string} media
|
|
2041
|
+
* @param {!Array.<number>} startTimes
|
|
2042
|
+
* @param {(function(!shaka.media.SegmentReference))=} modifyFn
|
|
2043
|
+
*/
|
|
2044
|
+
async function test(media, startTimes, modifyFn) {
|
|
2045
|
+
const master = [
|
|
2046
|
+
'#EXTM3U\n',
|
|
2047
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,vtt",',
|
|
2048
|
+
'RESOLUTION=960x540,FRAME-RATE=60\n',
|
|
2049
|
+
'video\n',
|
|
2050
|
+
].join('');
|
|
2051
|
+
|
|
2052
|
+
const segments = [];
|
|
2053
|
+
for (let i = 0; i < startTimes.length - 1; i++) {
|
|
2054
|
+
const startTime = startTimes[i];
|
|
2055
|
+
const endTime = startTimes[i + 1];
|
|
2056
|
+
const reference = makeReference(startTime, endTime, startTime);
|
|
2057
|
+
if (modifyFn) {
|
|
2058
|
+
modifyFn(reference);
|
|
2059
|
+
}
|
|
2060
|
+
segments.push(reference);
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
2064
|
+
manifest.anyTimeline();
|
|
2065
|
+
manifest.addPartialVariant((variant) => {
|
|
2066
|
+
variant.addPartialStream(ContentType.VIDEO, (stream) => {
|
|
2067
|
+
stream.segmentIndex = new shaka.media.SegmentIndex(segments);
|
|
2068
|
+
});
|
|
2069
|
+
});
|
|
2070
|
+
manifest.sequenceMode = true;
|
|
2071
|
+
});
|
|
2072
|
+
|
|
2073
|
+
fakeNetEngine
|
|
2074
|
+
.setResponseText('test:/master', master)
|
|
2075
|
+
.setResponseText('test:/video', media)
|
|
2076
|
+
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
2077
|
+
.setResponseValue('test:/main.mp4', segmentData);
|
|
2078
|
+
|
|
2079
|
+
const actual = await parser.start('test:/master', playerInterface);
|
|
2080
|
+
expect(actual).toEqual(manifest);
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
it('from EXT-X-PROGRAM-DATE-TIME', async () => {
|
|
2084
|
+
await test([
|
|
2085
|
+
'#EXTM3U\n',
|
|
2086
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
2087
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
2088
|
+
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:05.00Z\n',
|
|
2089
|
+
'#EXTINF:5,\n',
|
|
2090
|
+
'main.mp4\n',
|
|
2091
|
+
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:10.00Z\n',
|
|
2092
|
+
'#EXTINF:5,\n',
|
|
2093
|
+
'main.mp4\n',
|
|
2094
|
+
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:15.00Z\n',
|
|
2095
|
+
'#EXTINF:5,\n',
|
|
2096
|
+
'main.mp4\n',
|
|
2097
|
+
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:20.00Z\n',
|
|
2098
|
+
'#EXTINF:5,\n',
|
|
2099
|
+
'main.mp4\n',
|
|
2100
|
+
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:25.00Z\n',
|
|
2101
|
+
'#EXTINF:5,\n',
|
|
2102
|
+
'main.mp4',
|
|
2103
|
+
].join(''), [0, 5, 10, 15, 20, 25]);
|
|
2104
|
+
});
|
|
2105
|
+
|
|
2106
|
+
it('when some EXT-X-PROGRAM-DATE-TIME values are missing', async () => {
|
|
2107
|
+
await test([
|
|
2108
|
+
'#EXTM3U\n',
|
|
2109
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
2110
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
2111
|
+
'#EXTINF:2,\n',
|
|
2112
|
+
'main.mp4\n',
|
|
2113
|
+
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:10.00Z\n',
|
|
2114
|
+
'#EXTINF:5,\n',
|
|
2115
|
+
'main.mp4\n',
|
|
2116
|
+
'#EXTINF:5,\n',
|
|
2117
|
+
'main.mp4\n',
|
|
2118
|
+
'#EXTINF:5,\n',
|
|
2119
|
+
'main.mp4\n',
|
|
2120
|
+
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:25.00Z\n',
|
|
2121
|
+
'#EXTINF:2,\n',
|
|
2122
|
+
'main.mp4\n',
|
|
2123
|
+
'#EXTINF:4,\n',
|
|
2124
|
+
'main.mp4',
|
|
2125
|
+
].join(''), [0, 2, 7, 12, 17, 19, 23]);
|
|
2126
|
+
});
|
|
2127
|
+
|
|
2128
|
+
it('except when ignoreManifestProgramDateTime is set', async () => {
|
|
2129
|
+
const config = shaka.util.PlayerConfiguration.createDefault().manifest;
|
|
2130
|
+
config.hls.ignoreManifestProgramDateTime = true;
|
|
2131
|
+
parser.configure(config);
|
|
2132
|
+
await test([
|
|
2133
|
+
'#EXTM3U\n',
|
|
2134
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
2135
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
2136
|
+
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:05.00Z\n',
|
|
2137
|
+
'#EXTINF:5,\n',
|
|
2138
|
+
'main.mp4\n',
|
|
2139
|
+
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:10.00Z\n',
|
|
2140
|
+
'#EXTINF:5,\n',
|
|
2141
|
+
'main.mp4\n',
|
|
2142
|
+
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:15.00Z\n',
|
|
2143
|
+
'#EXTINF:5,\n',
|
|
2144
|
+
'main.mp4\n',
|
|
2145
|
+
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:20.00Z\n',
|
|
2146
|
+
'#EXTINF:5,\n',
|
|
2147
|
+
'main.mp4\n',
|
|
2148
|
+
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:25.00Z\n',
|
|
2149
|
+
'#EXTINF:5,\n',
|
|
2150
|
+
'main.mp4',
|
|
2151
|
+
].join(''), [0, 5, 10, 15, 20, 25], (reference) => {
|
|
2152
|
+
reference.syncTime = null;
|
|
2153
|
+
});
|
|
2154
|
+
});
|
|
2155
|
+
|
|
2156
|
+
it('when there are partial segments', async () => {
|
|
2157
|
+
playerInterface.isLowLatencyMode = () => true;
|
|
2158
|
+
await test([
|
|
2159
|
+
'#EXTM3U\n',
|
|
2160
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
2161
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
2162
|
+
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:05.00Z\n',
|
|
2163
|
+
'#EXTINF:5,\n',
|
|
2164
|
+
'main.mp4\n',
|
|
2165
|
+
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:10.00Z\n',
|
|
2166
|
+
'#EXTINF:5,\n',
|
|
2167
|
+
'main.mp4\n',
|
|
2168
|
+
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:15.00Z\n',
|
|
2169
|
+
'#EXT-X-PART:DURATION=2.5,URI="main.mp4"\n',
|
|
2170
|
+
'#EXT-X-PART:DURATION=2.5,URI="main.mp4"\n',
|
|
2171
|
+
'#EXTINF:5,\n',
|
|
2172
|
+
'main.mp4\n',
|
|
2173
|
+
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:20.00Z\n',
|
|
2174
|
+
'#EXTINF:5,\n',
|
|
2175
|
+
'main.mp4\n',
|
|
2176
|
+
'#EXT-X-PROGRAM-DATE-TIME:2000-01-01T00:00:25.00Z\n',
|
|
2177
|
+
'#EXTINF:5,\n',
|
|
2178
|
+
'main.mp4',
|
|
2179
|
+
].join(''), [0, 5, 10, 15, 20, 25], (reference) => {
|
|
2180
|
+
if (reference.startTime == 10) {
|
|
2181
|
+
reference.partialReferences = [
|
|
2182
|
+
makeReference(10, 12.5, 10),
|
|
2183
|
+
makeReference(12.5, 15, 12.5),
|
|
2184
|
+
];
|
|
2185
|
+
}
|
|
2186
|
+
});
|
|
2187
|
+
});
|
|
2188
|
+
});
|
|
2189
|
+
|
|
1925
2190
|
it('drops failed text streams when configured to', async () => {
|
|
1926
2191
|
const master = [
|
|
1927
2192
|
'#EXTM3U\n',
|
|
@@ -1945,6 +2210,7 @@ describe('HlsParser', () => {
|
|
|
1945
2210
|
manifest.addPartialVariant((variant) => {
|
|
1946
2211
|
variant.addPartialStream(ContentType.VIDEO);
|
|
1947
2212
|
});
|
|
2213
|
+
manifest.sequenceMode = true;
|
|
1948
2214
|
});
|
|
1949
2215
|
|
|
1950
2216
|
fakeNetEngine
|
|
@@ -1982,6 +2248,7 @@ describe('HlsParser', () => {
|
|
|
1982
2248
|
manifest.addPartialVariant((variant) => {
|
|
1983
2249
|
variant.addPartialStream(ContentType.VIDEO);
|
|
1984
2250
|
});
|
|
2251
|
+
manifest.sequenceMode = true;
|
|
1985
2252
|
});
|
|
1986
2253
|
|
|
1987
2254
|
fakeNetEngine
|
|
@@ -2024,6 +2291,7 @@ describe('HlsParser', () => {
|
|
|
2024
2291
|
});
|
|
2025
2292
|
variant.addPartialStream(ContentType.AUDIO);
|
|
2026
2293
|
});
|
|
2294
|
+
manifest.sequenceMode = true;
|
|
2027
2295
|
});
|
|
2028
2296
|
|
|
2029
2297
|
await testHlsParser(master, media, manifest);
|
|
@@ -2108,6 +2376,7 @@ describe('HlsParser', () => {
|
|
|
2108
2376
|
stream.mime('audio/mp4', 'mp4a');
|
|
2109
2377
|
});
|
|
2110
2378
|
});
|
|
2379
|
+
manifest.sequenceMode = true;
|
|
2111
2380
|
});
|
|
2112
2381
|
|
|
2113
2382
|
await testHlsParser(master, media, manifest);
|
|
@@ -2203,6 +2472,7 @@ describe('HlsParser', () => {
|
|
|
2203
2472
|
stream.language = 'en';
|
|
2204
2473
|
});
|
|
2205
2474
|
});
|
|
2475
|
+
manifest.sequenceMode = true;
|
|
2206
2476
|
});
|
|
2207
2477
|
|
|
2208
2478
|
fakeNetEngine
|
|
@@ -2261,6 +2531,7 @@ describe('HlsParser', () => {
|
|
|
2261
2531
|
});
|
|
2262
2532
|
});
|
|
2263
2533
|
});
|
|
2534
|
+
manifest.sequenceMode = true;
|
|
2264
2535
|
});
|
|
2265
2536
|
|
|
2266
2537
|
await testHlsParser(master, media, manifest);
|
|
@@ -2300,6 +2571,44 @@ describe('HlsParser', () => {
|
|
|
2300
2571
|
});
|
|
2301
2572
|
});
|
|
2302
2573
|
});
|
|
2574
|
+
manifest.sequenceMode = true;
|
|
2575
|
+
});
|
|
2576
|
+
|
|
2577
|
+
await testHlsParser(master, media, manifest);
|
|
2578
|
+
});
|
|
2579
|
+
|
|
2580
|
+
it('constructs DrmInfo for FairPlay', async () => {
|
|
2581
|
+
const master = [
|
|
2582
|
+
'#EXTM3U\n',
|
|
2583
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",',
|
|
2584
|
+
'RESOLUTION=960x540,FRAME-RATE=60\n',
|
|
2585
|
+
'video\n',
|
|
2586
|
+
].join('');
|
|
2587
|
+
|
|
2588
|
+
const media = [
|
|
2589
|
+
'#EXTM3U\n',
|
|
2590
|
+
'#EXT-X-TARGETDURATION:6\n',
|
|
2591
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
2592
|
+
'#EXT-X-KEY:METHOD=SAMPLE-AES-CTR,',
|
|
2593
|
+
'KEYFORMAT="com.apple.streamingkeydelivery",',
|
|
2594
|
+
'URI="skd://f93d4e700d7ddde90529a27735d9e7cb",\n',
|
|
2595
|
+
'#EXT-X-MAP:URI="init.mp4"\n',
|
|
2596
|
+
'#EXTINF:5,\n',
|
|
2597
|
+
'#EXT-X-BYTERANGE:121090@616\n',
|
|
2598
|
+
'main.mp4',
|
|
2599
|
+
].join('');
|
|
2600
|
+
|
|
2601
|
+
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
2602
|
+
manifest.anyTimeline();
|
|
2603
|
+
manifest.addPartialVariant((variant) => {
|
|
2604
|
+
variant.addPartialStream(ContentType.VIDEO, (stream) => {
|
|
2605
|
+
stream.encrypted = true;
|
|
2606
|
+
stream.addDrmInfo('com.apple.fps', (drmInfo) => {
|
|
2607
|
+
drmInfo.addInitData('sinf', new Uint8Array(0));
|
|
2608
|
+
});
|
|
2609
|
+
});
|
|
2610
|
+
});
|
|
2611
|
+
manifest.sequenceMode = true;
|
|
2303
2612
|
});
|
|
2304
2613
|
|
|
2305
2614
|
await testHlsParser(master, media, manifest);
|
|
@@ -2333,6 +2642,7 @@ describe('HlsParser', () => {
|
|
|
2333
2642
|
stream.mime('audio/mp4', 'mp4a');
|
|
2334
2643
|
});
|
|
2335
2644
|
});
|
|
2645
|
+
manifest.sequenceMode = true;
|
|
2336
2646
|
});
|
|
2337
2647
|
|
|
2338
2648
|
fakeNetEngine.setHeaders(
|
|
@@ -2501,6 +2811,34 @@ describe('HlsParser', () => {
|
|
|
2501
2811
|
});
|
|
2502
2812
|
});
|
|
2503
2813
|
|
|
2814
|
+
it('if FairPlay encryption with MSE and mp2t content', async () => {
|
|
2815
|
+
const master = [
|
|
2816
|
+
'#EXTM3U\n',
|
|
2817
|
+
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",',
|
|
2818
|
+
'RESOLUTION=960x540,FRAME-RATE=60\n',
|
|
2819
|
+
'video\n',
|
|
2820
|
+
].join('');
|
|
2821
|
+
|
|
2822
|
+
const media = [
|
|
2823
|
+
'#EXTM3U\n',
|
|
2824
|
+
'#EXT-X-TARGETDURATION:6\n',
|
|
2825
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
2826
|
+
'#EXT-X-KEY:METHOD=SAMPLE-AES-CTR,',
|
|
2827
|
+
'KEYFORMAT="com.apple.streamingkeydelivery",',
|
|
2828
|
+
'URI="skd://f93d4e700d7ddde90529a27735d9e7cb",\n',
|
|
2829
|
+
'#EXTINF:5,\n',
|
|
2830
|
+
'#EXT-X-BYTERANGE:121090@616\n',
|
|
2831
|
+
'main.ts',
|
|
2832
|
+
].join('');
|
|
2833
|
+
|
|
2834
|
+
const error = new shaka.util.Error(
|
|
2835
|
+
shaka.util.Error.Severity.CRITICAL,
|
|
2836
|
+
shaka.util.Error.Category.MANIFEST,
|
|
2837
|
+
Code.HLS_MSE_ENCRYPTED_MP2T_NOT_SUPPORTED);
|
|
2838
|
+
|
|
2839
|
+
await verifyError(master, media, error);
|
|
2840
|
+
});
|
|
2841
|
+
|
|
2504
2842
|
describe('if required tags are missing', () => {
|
|
2505
2843
|
/**
|
|
2506
2844
|
* @param {string} master
|
|
@@ -2539,261 +2877,6 @@ describe('HlsParser', () => {
|
|
|
2539
2877
|
});
|
|
2540
2878
|
}); // Errors out
|
|
2541
2879
|
|
|
2542
|
-
describe('getStartTime_', () => {
|
|
2543
|
-
/** @type {number} */
|
|
2544
|
-
let segmentDataStartTime;
|
|
2545
|
-
/** @type {!Uint8Array} */
|
|
2546
|
-
let tsSegmentData;
|
|
2547
|
-
/** @type {!Uint8Array} */
|
|
2548
|
-
let nullTsPacketData;
|
|
2549
|
-
|
|
2550
|
-
const master = [
|
|
2551
|
-
'#EXTM3U\n',
|
|
2552
|
-
'#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",',
|
|
2553
|
-
'RESOLUTION=960x540,FRAME-RATE=60\n',
|
|
2554
|
-
'video',
|
|
2555
|
-
].join('');
|
|
2556
|
-
|
|
2557
|
-
const media = [
|
|
2558
|
-
'#EXTM3U\n',
|
|
2559
|
-
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
2560
|
-
'#EXT-X-MAP:URI="init.mp4"\n',
|
|
2561
|
-
'#EXTINF:5,\n',
|
|
2562
|
-
'#EXT-X-BYTERANGE:121090@616\n',
|
|
2563
|
-
'main.mp4',
|
|
2564
|
-
].join('');
|
|
2565
|
-
|
|
2566
|
-
// TODO: Add separate tests to cover correct handling of BYTERANGE in
|
|
2567
|
-
// constructing references. Here it is covered incidentally.
|
|
2568
|
-
const expectedStartByte = 616;
|
|
2569
|
-
const expectedEndByte = 121705;
|
|
2570
|
-
// Nit: this value is an implementation detail of the fix for #1106
|
|
2571
|
-
const partialEndByte = expectedStartByte + 2048 - 1;
|
|
2572
|
-
|
|
2573
|
-
beforeEach(() => {
|
|
2574
|
-
// TODO: use StreamGenerator?
|
|
2575
|
-
segmentData = new Uint8Array([
|
|
2576
|
-
0x00, 0x00, 0x00, 0x24, // size (36)
|
|
2577
|
-
0x6D, 0x6F, 0x6F, 0x66, // type (moof)
|
|
2578
|
-
0x00, 0x00, 0x00, 0x1C, // traf size (28)
|
|
2579
|
-
0x74, 0x72, 0x61, 0x66, // type (traf)
|
|
2580
|
-
0x00, 0x00, 0x00, 0x14, // tfdt size (20)
|
|
2581
|
-
0x74, 0x66, 0x64, 0x74, // type (tfdt)
|
|
2582
|
-
0x01, 0x00, 0x00, 0x00, // version and flags
|
|
2583
|
-
|
|
2584
|
-
0x00, 0x00, 0x00, 0x00, // baseMediaDecodeTime first 4 bytes
|
|
2585
|
-
0x00, 0x00, 0x07, 0xd0, // baseMediaDecodeTime last 4 bytes (2000)
|
|
2586
|
-
]);
|
|
2587
|
-
tsSegmentData = new Uint8Array([
|
|
2588
|
-
0x47, // TS sync byte (fixed value)
|
|
2589
|
-
0x41, 0x01, // not corrupt, payload follows, packet ID 257
|
|
2590
|
-
0x10, // not scrambled, no adaptation field, payload only, seq #0
|
|
2591
|
-
0x00, 0x00, 0x01, // PES start code (fixed value)
|
|
2592
|
-
0xe0, // stream ID (video stream 0)
|
|
2593
|
-
0x00, 0x00, // PES packet length (doesn't matter)
|
|
2594
|
-
0x80, // marker bits (fixed value), not scrambled, not priority
|
|
2595
|
-
0x80, // PTS only, no DTS, other flags 0 (don't matter)
|
|
2596
|
-
0x05, // remaining PES header length == 5 (one timestamp)
|
|
2597
|
-
0x21, 0x00, 0x0b, 0x7e, 0x41, // PTS = 180000, encoded into 5 bytes
|
|
2598
|
-
]);
|
|
2599
|
-
// 180000 (TS PTS) divided by fixed TS timescale (90000) = 2s.
|
|
2600
|
-
// 2000 (MP4 PTS) divided by parsed MP4 timescale (1000) = 2s.
|
|
2601
|
-
segmentDataStartTime = 2;
|
|
2602
|
-
nullTsPacketData = new Uint8Array([
|
|
2603
|
-
0x47, // TS sync byte (fixed value)
|
|
2604
|
-
0x1f, 0xff, // null packet (packet ID 8191)
|
|
2605
|
-
]);
|
|
2606
|
-
});
|
|
2607
|
-
|
|
2608
|
-
it('parses start time from mp4 segment', async () => {
|
|
2609
|
-
fakeNetEngine
|
|
2610
|
-
.setResponseText('test:/master', master)
|
|
2611
|
-
.setResponseText('test:/video', media)
|
|
2612
|
-
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
2613
|
-
.setResponseValue('test:/main.mp4', segmentData);
|
|
2614
|
-
|
|
2615
|
-
const expectedRef = ManifestParser.makeReference(
|
|
2616
|
-
/* uri= */ 'test:/main.mp4',
|
|
2617
|
-
/* startTime= */ 0,
|
|
2618
|
-
/* endTime= */ 5,
|
|
2619
|
-
/* baseUri= */ '',
|
|
2620
|
-
expectedStartByte,
|
|
2621
|
-
expectedEndByte);
|
|
2622
|
-
// In VOD content, we set the timestampOffset to align the
|
|
2623
|
-
// content to presentation time 0.
|
|
2624
|
-
expectedRef.timestampOffset = -segmentDataStartTime;
|
|
2625
|
-
|
|
2626
|
-
const manifest = await parser.start('test:/master', playerInterface);
|
|
2627
|
-
const video = manifest.variants[0].video;
|
|
2628
|
-
await video.createSegmentIndex();
|
|
2629
|
-
ManifestParser.verifySegmentIndex(video, [expectedRef]);
|
|
2630
|
-
|
|
2631
|
-
// Make sure the segment data was fetched with the correct byte
|
|
2632
|
-
// range.
|
|
2633
|
-
fakeNetEngine.expectRangeRequest(
|
|
2634
|
-
'test:/main.mp4',
|
|
2635
|
-
expectedStartByte,
|
|
2636
|
-
partialEndByte);
|
|
2637
|
-
});
|
|
2638
|
-
|
|
2639
|
-
it('parses start time from ts segments', async () => {
|
|
2640
|
-
const tsMediaPlaylist = media.replace(/\.mp4/g, '.ts');
|
|
2641
|
-
|
|
2642
|
-
fakeNetEngine
|
|
2643
|
-
.setResponseText('test:/master', master)
|
|
2644
|
-
.setResponseText('test:/video', tsMediaPlaylist)
|
|
2645
|
-
.setResponseValue('test:/main.ts', tsSegmentData);
|
|
2646
|
-
|
|
2647
|
-
const expectedRef = ManifestParser.makeReference(
|
|
2648
|
-
/* uri= */ 'test:/main.ts',
|
|
2649
|
-
/* startTime= */ 0,
|
|
2650
|
-
/* endTime= */ 5,
|
|
2651
|
-
/* baseUri= */ '',
|
|
2652
|
-
expectedStartByte,
|
|
2653
|
-
expectedEndByte);
|
|
2654
|
-
// In VOD content, we set the timestampOffset to align the
|
|
2655
|
-
// content to presentation time 0.
|
|
2656
|
-
expectedRef.timestampOffset = -segmentDataStartTime;
|
|
2657
|
-
|
|
2658
|
-
const manifest = await parser.start('test:/master', playerInterface);
|
|
2659
|
-
const video = manifest.variants[0].video;
|
|
2660
|
-
await video.createSegmentIndex();
|
|
2661
|
-
ManifestParser.verifySegmentIndex(video, [expectedRef]);
|
|
2662
|
-
|
|
2663
|
-
// Make sure the segment data was fetched with the correct byte
|
|
2664
|
-
// range.
|
|
2665
|
-
fakeNetEngine.expectRangeRequest(
|
|
2666
|
-
'test:/main.ts',
|
|
2667
|
-
expectedStartByte,
|
|
2668
|
-
partialEndByte);
|
|
2669
|
-
});
|
|
2670
|
-
|
|
2671
|
-
it('parses start time from ts segments with null packets', async () => {
|
|
2672
|
-
const tsMediaPlaylist = media.replace(/\.mp4/g, '.ts');
|
|
2673
|
-
|
|
2674
|
-
// Each packet is 188 bytes, so allocate space for 3.
|
|
2675
|
-
const tsSegmentWithNullPackets = new Uint8Array(188 * 3);
|
|
2676
|
-
// The first two are "null" packets.
|
|
2677
|
-
tsSegmentWithNullPackets.set(nullTsPacketData, /* offset= */ 0);
|
|
2678
|
-
tsSegmentWithNullPackets.set(nullTsPacketData, /* offset= */ 188);
|
|
2679
|
-
// The third has a timestamp.
|
|
2680
|
-
tsSegmentWithNullPackets.set(tsSegmentData, /* offset= */ 188 * 2);
|
|
2681
|
-
|
|
2682
|
-
fakeNetEngine
|
|
2683
|
-
.setResponseText('test:/master', master)
|
|
2684
|
-
.setResponseText('test:/video', tsMediaPlaylist)
|
|
2685
|
-
.setResponseValue('test:/main.ts', tsSegmentWithNullPackets);
|
|
2686
|
-
|
|
2687
|
-
const expectedRef = ManifestParser.makeReference(
|
|
2688
|
-
/* uri= */ 'test:/main.ts',
|
|
2689
|
-
/* startTime= */ 0,
|
|
2690
|
-
/* endTime= */ 5,
|
|
2691
|
-
/* baseUri= */ '',
|
|
2692
|
-
expectedStartByte,
|
|
2693
|
-
expectedEndByte);
|
|
2694
|
-
// In VOD content, we set the timestampOffset to align the
|
|
2695
|
-
// content to presentation time 0.
|
|
2696
|
-
expectedRef.timestampOffset = -segmentDataStartTime;
|
|
2697
|
-
|
|
2698
|
-
const manifest = await parser.start('test:/master', playerInterface);
|
|
2699
|
-
const video = manifest.variants[0].video;
|
|
2700
|
-
await video.createSegmentIndex();
|
|
2701
|
-
ManifestParser.verifySegmentIndex(video, [expectedRef]);
|
|
2702
|
-
|
|
2703
|
-
// Make sure the segment data was fetched with the correct byte
|
|
2704
|
-
// range.
|
|
2705
|
-
fakeNetEngine.expectRangeRequest(
|
|
2706
|
-
'test:/main.ts',
|
|
2707
|
-
expectedStartByte,
|
|
2708
|
-
partialEndByte);
|
|
2709
|
-
});
|
|
2710
|
-
|
|
2711
|
-
// We want to make sure that we can interrupt the parser while it is getting
|
|
2712
|
-
// the start time. This is a regression test for Issue #1788 where
|
|
2713
|
-
// interrupting the partial network request would be misinterpreted as the
|
|
2714
|
-
// server not supporting range requests.
|
|
2715
|
-
it('can be interrupted', async () => {
|
|
2716
|
-
fakeNetEngine
|
|
2717
|
-
.setResponseText('test:/master', master)
|
|
2718
|
-
.setResponseText('test:/video', media)
|
|
2719
|
-
.setResponseValue('test:/init.mp4', initSegmentData);
|
|
2720
|
-
|
|
2721
|
-
// We are assuming that the time will be pulled out of the main mp4
|
|
2722
|
-
// segment, so if we see a request that has a range header, we will stop
|
|
2723
|
-
// the parser.
|
|
2724
|
-
/** @type {!Map.<string, !BufferSource>} */
|
|
2725
|
-
const responses = new Map();
|
|
2726
|
-
responses.set('test:/main.mp4', segmentData);
|
|
2727
|
-
responses.set('test:/init.mp4', initSegmentData);
|
|
2728
|
-
|
|
2729
|
-
responses.forEach((data, uri) => {
|
|
2730
|
-
fakeNetEngine.setResponse(uri, () => {
|
|
2731
|
-
// Now that we are stopping the parser, we don't want to see any more
|
|
2732
|
-
// requests. So if there is another request, fail the test.
|
|
2733
|
-
responses.forEach((data, uri) => {
|
|
2734
|
-
fakeNetEngine.setResponse(uri, fail);
|
|
2735
|
-
});
|
|
2736
|
-
|
|
2737
|
-
// Stop the parser, but don't wait on it or else we will hit deadlock.
|
|
2738
|
-
parser.stop();
|
|
2739
|
-
|
|
2740
|
-
return Promise.resolve(data);
|
|
2741
|
-
});
|
|
2742
|
-
});
|
|
2743
|
-
|
|
2744
|
-
const expected = Util.jasmineError(new shaka.util.Error(
|
|
2745
|
-
shaka.util.Error.Severity.CRITICAL,
|
|
2746
|
-
shaka.util.Error.Category.PLAYER,
|
|
2747
|
-
shaka.util.Error.Code.OPERATION_ABORTED));
|
|
2748
|
-
await expectAsync(parser.start('test:/master', playerInterface))
|
|
2749
|
-
.toBeRejectedWith(expected);
|
|
2750
|
-
});
|
|
2751
|
-
|
|
2752
|
-
it('sets duration with respect to presentation offset', async () => {
|
|
2753
|
-
fakeNetEngine
|
|
2754
|
-
.setResponseText('test:/master', master)
|
|
2755
|
-
.setResponseText('test:/video', media)
|
|
2756
|
-
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
2757
|
-
.setResponseValue('test:/main.mp4', segmentData);
|
|
2758
|
-
|
|
2759
|
-
const manifest = await parser.start('test:/master', playerInterface);
|
|
2760
|
-
const presentationTimeline = manifest.presentationTimeline;
|
|
2761
|
-
|
|
2762
|
-
const video = manifest.variants[0].video;
|
|
2763
|
-
await video.createSegmentIndex();
|
|
2764
|
-
goog.asserts.assert(video.segmentIndex != null, 'Null segmentIndex!');
|
|
2765
|
-
|
|
2766
|
-
const refs = Array.from(video.segmentIndex);
|
|
2767
|
-
expect(refs.length).toBe(1);
|
|
2768
|
-
|
|
2769
|
-
expect(refs[0].timestampOffset).toBe(-segmentDataStartTime);
|
|
2770
|
-
// The duration should be set to the sum of the segment durations (5),
|
|
2771
|
-
// even though the endTime of the segment is larger.
|
|
2772
|
-
expect(refs[0].endTime - refs[0].startTime).toBe(5);
|
|
2773
|
-
expect(presentationTimeline.getDuration()).toBe(5);
|
|
2774
|
-
});
|
|
2775
|
-
|
|
2776
|
-
it('forces full segment request', async () => {
|
|
2777
|
-
fakeNetEngine
|
|
2778
|
-
.setResponseText('test:/master', master)
|
|
2779
|
-
.setResponseText('test:/video', media)
|
|
2780
|
-
.setResponseValue('test:/init.mp4', initSegmentData)
|
|
2781
|
-
.setResponseValue('test:/main.mp4', segmentData);
|
|
2782
|
-
|
|
2783
|
-
const config = shaka.util.PlayerConfiguration.createDefault().manifest;
|
|
2784
|
-
config.hls.useFullSegmentsForStartTime = true;
|
|
2785
|
-
parser.configure(config);
|
|
2786
|
-
await parser.start('test:/master', playerInterface);
|
|
2787
|
-
|
|
2788
|
-
// Make sure the segment data was fetched with the correct byte
|
|
2789
|
-
// range.
|
|
2790
|
-
fakeNetEngine.expectRangeRequest(
|
|
2791
|
-
'test:/main.mp4',
|
|
2792
|
-
expectedStartByte,
|
|
2793
|
-
expectedEndByte);
|
|
2794
|
-
});
|
|
2795
|
-
});
|
|
2796
|
-
|
|
2797
2880
|
it('correctly detects VOD streams as non-live', async () => {
|
|
2798
2881
|
const master = [
|
|
2799
2882
|
'#EXTM3U\n',
|
|
@@ -2944,7 +3027,7 @@ describe('HlsParser', () => {
|
|
|
2944
3027
|
expect(audio0).toBe(audio1);
|
|
2945
3028
|
});
|
|
2946
3029
|
|
|
2947
|
-
// https://github.com/
|
|
3030
|
+
// https://github.com/shaka-project/shaka-player/issues/1664
|
|
2948
3031
|
it('correctly resolves relative playlist URIs', async () => {
|
|
2949
3032
|
const master = [
|
|
2950
3033
|
'#EXTM3U\n',
|
|
@@ -2987,7 +3070,7 @@ describe('HlsParser', () => {
|
|
|
2987
3070
|
expect(manifest.variants.length).toBe(1);
|
|
2988
3071
|
});
|
|
2989
3072
|
|
|
2990
|
-
// https://github.com/
|
|
3073
|
+
// https://github.com/shaka-project/shaka-player/issues/1908
|
|
2991
3074
|
it('correctly pairs variants with multiple video and audio', async () => {
|
|
2992
3075
|
const master = [
|
|
2993
3076
|
'#EXTM3U\n',
|
|
@@ -3050,80 +3133,12 @@ describe('HlsParser', () => {
|
|
|
3050
3133
|
stream.language = 'fr';
|
|
3051
3134
|
});
|
|
3052
3135
|
});
|
|
3136
|
+
manifest.sequenceMode = true;
|
|
3053
3137
|
});
|
|
3054
3138
|
|
|
3055
3139
|
await testHlsParser(master, media, manifest);
|
|
3056
3140
|
});
|
|
3057
3141
|
|
|
3058
|
-
it('skips raw audio formats', async () => {
|
|
3059
|
-
const master = [
|
|
3060
|
-
'#EXTM3U\n',
|
|
3061
|
-
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",URI="audio1"\n',
|
|
3062
|
-
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",URI="audio2"\n',
|
|
3063
|
-
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",URI="audio3"\n',
|
|
3064
|
-
'#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",URI="audio4"\n',
|
|
3065
|
-
'#EXT-X-STREAM-INF:BANDWIDTH=400,CODECS="avc1,mp4a",',
|
|
3066
|
-
'RESOLUTION=1280x720,AUDIO="audio"\n',
|
|
3067
|
-
'video\n',
|
|
3068
|
-
].join('');
|
|
3069
|
-
|
|
3070
|
-
const videoMedia = [
|
|
3071
|
-
'#EXTM3U\n',
|
|
3072
|
-
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
3073
|
-
'#EXT-X-MAP:URI="v-init.mp4"\n',
|
|
3074
|
-
'#EXTINF:5,\n',
|
|
3075
|
-
'v1.mp4',
|
|
3076
|
-
].join('');
|
|
3077
|
-
|
|
3078
|
-
const audioMedia1 = [
|
|
3079
|
-
'#EXTM3U\n',
|
|
3080
|
-
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
3081
|
-
'#EXTINF:5,\n',
|
|
3082
|
-
'a1.mp3',
|
|
3083
|
-
].join('');
|
|
3084
|
-
|
|
3085
|
-
const audioMedia2 = [
|
|
3086
|
-
'#EXTM3U\n',
|
|
3087
|
-
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
3088
|
-
'#EXTINF:5,\n',
|
|
3089
|
-
'a1.aac',
|
|
3090
|
-
].join('');
|
|
3091
|
-
|
|
3092
|
-
const audioMedia3 = [
|
|
3093
|
-
'#EXTM3U\n',
|
|
3094
|
-
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
3095
|
-
'#EXTINF:5,\n',
|
|
3096
|
-
'a1.ac3',
|
|
3097
|
-
].join('');
|
|
3098
|
-
|
|
3099
|
-
const audioMedia4 = [
|
|
3100
|
-
'#EXTM3U\n',
|
|
3101
|
-
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
3102
|
-
'#EXTINF:5,\n',
|
|
3103
|
-
'a1.ec3',
|
|
3104
|
-
].join('');
|
|
3105
|
-
|
|
3106
|
-
fakeNetEngine
|
|
3107
|
-
.setResponseText('test:/master', master)
|
|
3108
|
-
.setResponseText('test:/video', videoMedia)
|
|
3109
|
-
.setResponseText('test:/audio1', audioMedia1)
|
|
3110
|
-
.setResponseText('test:/audio2', audioMedia2)
|
|
3111
|
-
.setResponseText('test:/audio3', audioMedia3)
|
|
3112
|
-
.setResponseText('test:/audio4', audioMedia4)
|
|
3113
|
-
.setResponseValue('test:/v-init.mp4', initSegmentData)
|
|
3114
|
-
.setResponseValue('test:/v1.mp4', segmentData);
|
|
3115
|
-
|
|
3116
|
-
const alwaysWarnSpy = jasmine.createSpy('shaka.log.alwaysWarn');
|
|
3117
|
-
shaka.log.alwaysWarn = shaka.test.Util.spyFunc(alwaysWarnSpy);
|
|
3118
|
-
|
|
3119
|
-
const manifest = await parser.start('test:/master', playerInterface);
|
|
3120
|
-
expect(manifest.variants.length).toBe(1);
|
|
3121
|
-
expect(manifest.variants[0].audio).toBe(null);
|
|
3122
|
-
|
|
3123
|
-
// We should log a warning when this happens.
|
|
3124
|
-
expect(alwaysWarnSpy).toHaveBeenCalled();
|
|
3125
|
-
});
|
|
3126
|
-
|
|
3127
3142
|
// Issue #1875
|
|
3128
3143
|
it('ignores audio groups on audio-only content', async () => {
|
|
3129
3144
|
// NOTE: To reproduce the original issue accurately, the two audio playlist
|
|
@@ -3159,6 +3174,7 @@ describe('HlsParser', () => {
|
|
|
3159
3174
|
stream.mime('audio/mp4', 'mp4a');
|
|
3160
3175
|
});
|
|
3161
3176
|
});
|
|
3177
|
+
manifest.sequenceMode = true;
|
|
3162
3178
|
});
|
|
3163
3179
|
|
|
3164
3180
|
fakeNetEngine
|
|
@@ -3341,6 +3357,7 @@ describe('HlsParser', () => {
|
|
|
3341
3357
|
stream.mime('audio/mp4', 'mp4a');
|
|
3342
3358
|
});
|
|
3343
3359
|
});
|
|
3360
|
+
manifest.sequenceMode = true;
|
|
3344
3361
|
});
|
|
3345
3362
|
|
|
3346
3363
|
await testHlsParser(master, media, manifest);
|
|
@@ -3378,6 +3395,7 @@ describe('HlsParser', () => {
|
|
|
3378
3395
|
stream.mime('audio/mp4', 'mp4a');
|
|
3379
3396
|
});
|
|
3380
3397
|
});
|
|
3398
|
+
manifest.sequenceMode = true;
|
|
3381
3399
|
});
|
|
3382
3400
|
|
|
3383
3401
|
await testHlsParser(master, media, manifest);
|
|
@@ -3416,6 +3434,7 @@ describe('HlsParser', () => {
|
|
|
3416
3434
|
stream.mime('audio/mp4', 'mp4a');
|
|
3417
3435
|
});
|
|
3418
3436
|
});
|
|
3437
|
+
manifest.sequenceMode = true;
|
|
3419
3438
|
});
|
|
3420
3439
|
|
|
3421
3440
|
await testHlsParser(master, media, manifest);
|
|
@@ -3455,6 +3474,7 @@ describe('HlsParser', () => {
|
|
|
3455
3474
|
stream.mime('audio/mp4', 'mp4a');
|
|
3456
3475
|
});
|
|
3457
3476
|
});
|
|
3477
|
+
manifest.sequenceMode = true;
|
|
3458
3478
|
});
|
|
3459
3479
|
|
|
3460
3480
|
await testHlsParser(master, media, manifest);
|
|
@@ -3485,4 +3505,54 @@ describe('HlsParser', () => {
|
|
|
3485
3505
|
jasmine.objectContaining(eventValue3));
|
|
3486
3506
|
});
|
|
3487
3507
|
});
|
|
3508
|
+
|
|
3509
|
+
it('parses media playlists directly', async () => {
|
|
3510
|
+
const media = [
|
|
3511
|
+
'#EXTM3U\n',
|
|
3512
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
3513
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
3514
|
+
'#EXTINF:5,\n',
|
|
3515
|
+
'#EXT-X-BYTERANGE:121090@616\n',
|
|
3516
|
+
'main.mp4',
|
|
3517
|
+
].join('');
|
|
3518
|
+
|
|
3519
|
+
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
3520
|
+
manifest.sequenceMode = true;
|
|
3521
|
+
manifest.anyTimeline();
|
|
3522
|
+
manifest.addPartialVariant((variant) => {
|
|
3523
|
+
variant.addPartialStream(ContentType.VIDEO, (stream) => {
|
|
3524
|
+
stream.mime('video/mp2t', 'avc1.42E01E, mp4a.40.2');
|
|
3525
|
+
});
|
|
3526
|
+
});
|
|
3527
|
+
});
|
|
3528
|
+
|
|
3529
|
+
await testHlsParser(media, '', manifest);
|
|
3530
|
+
});
|
|
3531
|
+
|
|
3532
|
+
it('honors hls.mediaPlaylistFullMimeType', async () => {
|
|
3533
|
+
const media = [
|
|
3534
|
+
'#EXTM3U\n',
|
|
3535
|
+
'#EXT-X-PLAYLIST-TYPE:VOD\n',
|
|
3536
|
+
'#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
|
|
3537
|
+
'#EXTINF:5,\n',
|
|
3538
|
+
'#EXT-X-BYTERANGE:121090@616\n',
|
|
3539
|
+
'main.mp4',
|
|
3540
|
+
].join('');
|
|
3541
|
+
|
|
3542
|
+
const config = shaka.util.PlayerConfiguration.createDefault().manifest;
|
|
3543
|
+
config.hls.mediaPlaylistFullMimeType = 'audio/webm; codecs="vorbis"';
|
|
3544
|
+
parser.configure(config);
|
|
3545
|
+
|
|
3546
|
+
const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
|
|
3547
|
+
manifest.sequenceMode = true;
|
|
3548
|
+
manifest.anyTimeline();
|
|
3549
|
+
manifest.addPartialVariant((variant) => {
|
|
3550
|
+
variant.addPartialStream(ContentType.AUDIO, (stream) => {
|
|
3551
|
+
stream.mime('audio/webm', 'vorbis');
|
|
3552
|
+
});
|
|
3553
|
+
});
|
|
3554
|
+
});
|
|
3555
|
+
|
|
3556
|
+
await testHlsParser(media, '', manifest);
|
|
3557
|
+
});
|
|
3488
3558
|
});
|