|
43 | 43 | } |
44 | 44 | } |
45 | 45 |
|
46 | | - function initializeHls() { |
47 | | - newVideo.removeEventListener('play', initializeHls); |
48 | | - var hls = new Hls({ autoStartLoad: false }); |
| 46 | + function addQualitySelector(videoElement, hlsInstance, availableLevels) { |
| 47 | + var qualitySelector = document.createElement('select'); |
| 48 | + qualitySelector.classList.add('quality-selector'); |
| 49 | + var defaultIndex = getIndexOfDefault(availableLevels.length); |
| 50 | + availableLevels.forEach(function (level, index) { |
| 51 | + var option = document.createElement('option'); |
| 52 | + option.value = index.toString(); |
| 53 | + var bitrate = (level.bitrate / 1_000).toFixed(0); |
| 54 | + option.text = level.height + 'p (' + bitrate + ' kbps)'; |
| 55 | + if (index === defaultIndex) { |
| 56 | + option.selected = "selected"; |
| 57 | + } |
| 58 | + qualitySelector.appendChild(option); |
| 59 | + }); |
| 60 | + qualitySelector.selectedIndex = defaultIndex; |
| 61 | + qualitySelector.addEventListener('change', function () { |
| 62 | + var selectedIndex = qualitySelector.selectedIndex; |
| 63 | + hlsInstance.nextLevel = selectedIndex; |
| 64 | + hlsInstance.startLoad(); |
| 65 | + }); |
| 66 | + |
| 67 | + videoElement.parentNode.appendChild(qualitySelector); |
| 68 | + } |
| 69 | + |
| 70 | + // hide manifest latency from play |
| 71 | + var observer = new IntersectionObserver(function (entries) { |
| 72 | + if (!entries[0].isIntersecting) return; |
| 73 | + observer.disconnect(); |
| 74 | + |
| 75 | + var hls = new Hls({ autoStartLoad: false }); // manifest only; segments deferred until startLoad() |
49 | 76 | hls.loadSource(playlist); |
50 | 77 | hls.attachMedia(newVideo); |
51 | | - hls.on(Hls.Events.MANIFEST_PARSED, function () { |
| 78 | + |
| 79 | + var manifestParsed = false; |
| 80 | + hls.once(Hls.Events.MANIFEST_PARSED, function () { |
52 | 81 | hls.loadLevel = getIndexOfDefault(hls.levels.length); |
53 | | - var availableLevels = hls.levels.map(function(level) { |
| 82 | + var availableLevels = hls.levels.map(function (level) { |
54 | 83 | return { |
55 | 84 | height: level.height, |
56 | 85 | width: level.width, |
57 | 86 | bitrate: level.bitrate, |
58 | 87 | }; |
59 | 88 | }); |
60 | | - |
61 | 89 | addQualitySelector(newVideo, hls, availableLevels); |
62 | | - |
63 | | - hls.startLoad(); |
64 | | - newVideo.play(); |
| 90 | + manifestParsed = true; |
65 | 91 | }); |
66 | 92 |
|
67 | 93 | hls.on(Hls.Events.ERROR, function (event, data) { |
|
83 | 109 |
|
84 | 110 | console.error("HLS error", data); |
85 | 111 | }); |
86 | | - } |
87 | 112 |
|
88 | | - function addQualitySelector(videoElement, hlsInstance, availableLevels) { |
89 | | - var qualitySelector = document.createElement('select'); |
90 | | - qualitySelector.classList.add('quality-selector'); |
91 | | - var defaultIndex = getIndexOfDefault(availableLevels.length); |
92 | | - availableLevels.forEach(function (level, index) { |
93 | | - var option = document.createElement('option'); |
94 | | - option.value = index.toString(); |
95 | | - var bitrate = (level.bitrate / 1_000).toFixed(0); |
96 | | - option.text = level.height + 'p (' + bitrate + ' kbps)'; |
97 | | - if (index === defaultIndex) { |
98 | | - option.selected = "selected"; |
| 113 | + function whenReady(fn) { |
| 114 | + if (manifestParsed) { |
| 115 | + fn(); |
| 116 | + } else { |
| 117 | + hls.once(Hls.Events.MANIFEST_PARSED, fn); |
99 | 118 | } |
100 | | - qualitySelector.appendChild(option); |
101 | | - }); |
102 | | - qualitySelector.selectedIndex = defaultIndex; |
103 | | - qualitySelector.addEventListener('change', function () { |
104 | | - var selectedIndex = qualitySelector.selectedIndex; |
105 | | - hlsInstance.nextLevel = selectedIndex; |
106 | | - hlsInstance.startLoad(); |
107 | | - }); |
| 119 | + } |
108 | 120 |
|
109 | | - videoElement.parentNode.appendChild(qualitySelector); |
110 | | - } |
| 121 | + function startPlayback() { |
| 122 | + whenReady(function () { hls.startLoad(); newVideo.play(); }); |
| 123 | + } |
111 | 124 |
|
112 | | - newVideo.addEventListener('play', initializeHls); |
| 125 | + if (autoplay) { |
| 126 | + startPlayback(); |
| 127 | + } else { |
| 128 | + newVideo.addEventListener('play', startPlayback, { once: true }); |
| 129 | + } |
| 130 | + }, { rootMargin: '200px' }); |
113 | 131 |
|
114 | | - if (autoplay) { |
115 | | - newVideo.play(); |
116 | | - } |
| 132 | + observer.observe(newVideo); |
117 | 133 | }); |
118 | 134 | } else { |
119 | 135 | var videos = document.querySelectorAll("video.hls_autoplay"); |
|
0 commit comments