Duration should be infinity for live playlists
Unless an explicit total duration tag is present in the playlist, set the duration to Infinity for live HLS. Document iOS behavior for live streams.
Showing
3 changed files
with
28 additions
and
2 deletions
1 | # Live HLS Research | 1 | # Live HLS Research |
2 | This document is a collection of notes on Live HLS implementations in the wild. | 2 | This document is a collection of notes on Live HLS implementations in the wild. |
3 | 3 | ||
4 | There are two varieties of Live HLS. In the first, playlists are | ||
5 | persistent and strictly appended to. In the alternative form, the | ||
6 | maximum number of segments in a playlist is relatively stable and an | ||
7 | old segment is removed every time a new segment becomes available. | ||
8 | |||
9 | On iOS devices, both stream types report a duration of `Infinity`. The | ||
10 | `currentTime` is equal to the amount of the stream that has been | ||
11 | played back on the device. | ||
12 | |||
4 | ## Akamai HD2 | 13 | ## Akamai HD2 |
5 | 14 | ||
6 | ## OnceLIVE | 15 | ## OnceLIVE |
16 | "Sliding window" live streams. | ||
7 | 17 | ||
8 | ### Variant Playlists | 18 | ### Variant Playlists |
9 | Once variant playlists look like standard HLS variant playlists. | 19 | Once variant playlists look like standard HLS variant playlists. | ... | ... |
... | @@ -132,6 +132,11 @@ var | ... | @@ -132,6 +132,11 @@ var |
132 | duration = 0, | 132 | duration = 0, |
133 | i = playlist.segments.length, | 133 | i = playlist.segments.length, |
134 | segment; | 134 | segment; |
135 | // duration should be Infinity for live playlists | ||
136 | if (!playlist.endList) { | ||
137 | return window.Infinity; | ||
138 | } | ||
139 | |||
135 | while (i--) { | 140 | while (i--) { |
136 | segment = playlist.segments[i]; | 141 | segment = playlist.segments[i]; |
137 | duration += segment.duration || playlist.targetDuration || 0; | 142 | duration += segment.duration || playlist.targetDuration || 0; | ... | ... |
... | @@ -181,13 +181,15 @@ test('calculates the duration if needed', function() { | ... | @@ -181,13 +181,15 @@ test('calculates the duration if needed', function() { |
181 | } | 181 | } |
182 | durations.push(duration); | 182 | durations.push(duration); |
183 | }; | 183 | }; |
184 | player.hls('http://example.com/manifest/liveMissingSegmentDuration.m3u8'); | 184 | player.hls('http://example.com/manifest/missingExtinf.m3u8'); |
185 | videojs.mediaSources[player.currentSrc()].trigger({ | 185 | videojs.mediaSources[player.currentSrc()].trigger({ |
186 | type: 'sourceopen' | 186 | type: 'sourceopen' |
187 | }); | 187 | }); |
188 | 188 | ||
189 | strictEqual(durations.length, 1, 'duration is set'); | 189 | strictEqual(durations.length, 1, 'duration is set'); |
190 | strictEqual(durations[0], 6.64 + (2 * 8), 'duration is calculated'); | 190 | strictEqual(durations[0], |
191 | player.hls.media.segments.length * 10, | ||
192 | 'duration is calculated'); | ||
191 | }); | 193 | }); |
192 | 194 | ||
193 | test('starts downloading a segment on loadedmetadata', function() { | 195 | test('starts downloading a segment on loadedmetadata', function() { |
... | @@ -890,6 +892,15 @@ test('reloads live playlists', function() { | ... | @@ -890,6 +892,15 @@ test('reloads live playlists', function() { |
890 | 'waited one target duration'); | 892 | 'waited one target duration'); |
891 | }); | 893 | }); |
892 | 894 | ||
895 | test('duration is Infinity for live playlists', function() { | ||
896 | player.hls('manifest/missingEndlist.m3u8'); | ||
897 | videojs.mediaSources[player.currentSrc()].trigger({ | ||
898 | type: 'sourceopen' | ||
899 | }); | ||
900 | |||
901 | strictEqual(Infinity, player.duration(), 'duration is infinity'); | ||
902 | }); | ||
903 | |||
893 | test('does not reload playlists with an endlist tag', function() { | 904 | test('does not reload playlists with an endlist tag', function() { |
894 | var callbacks = []; | 905 | var callbacks = []; |
895 | // capture timeouts | 906 | // capture timeouts | ... | ... |
-
Please register or sign in to post a comment