Do not calculate totalDuration at parse time
Unless a comment specifies the total duration, do not add the property to the parsed manifest object. Also, do not default it to zero if it is not defined in the manifest. Instead, calculate the total duration from the target duration and segment metadata whenever a new playlist is selected.
Showing
38 changed files
with
125 additions
and
86 deletions
... | @@ -298,8 +298,7 @@ | ... | @@ -298,8 +298,7 @@ |
298 | 298 | ||
299 | // the manifest is empty until the parse stream begins delivering data | 299 | // the manifest is empty until the parse stream begins delivering data |
300 | this.manifest = { | 300 | this.manifest = { |
301 | allowCache: true, | 301 | allowCache: true |
302 | totalDuration: 0 | ||
303 | }; | 302 | }; |
304 | 303 | ||
305 | // update the manifest with the m3u8 entry from the parse stream | 304 | // update the manifest with the m3u8 entry from the parse stream |
... | @@ -406,24 +405,6 @@ | ... | @@ -406,24 +405,6 @@ |
406 | return; | 405 | return; |
407 | } | 406 | } |
408 | this.manifest.totalDuration = entry.duration; | 407 | this.manifest.totalDuration = entry.duration; |
409 | }, | ||
410 | 'endlist': function() { | ||
411 | var i, calculatedDuration = 0; | ||
412 | if (this.manifest.totalDuration === 0) { | ||
413 | for (i = 0; i < this.manifest.segments.length; i++) { | ||
414 | if (this.manifest.segments[i].duration) { | ||
415 | calculatedDuration += this.manifest.segments[i].duration; | ||
416 | } else if (this.manifest.targetDuration > 0) { | ||
417 | calculatedDuration += this.manifest.targetDuration; | ||
418 | } else { | ||
419 | calculatedDuration += 0; | ||
420 | } | ||
421 | } | ||
422 | this.manifest.totalDuration = calculatedDuration; | ||
423 | this.trigger('info', { | ||
424 | message: 'updating total duration to use a calculated value' | ||
425 | }); | ||
426 | } | ||
427 | } | 408 | } |
428 | })[entry.tagType] || noop).call(self); | 409 | })[entry.tagType] || noop).call(self); |
429 | }, | 410 | }, | ... | ... |
... | @@ -39,7 +39,7 @@ var | ... | @@ -39,7 +39,7 @@ var |
39 | * @param time | 39 | * @param time |
40 | * @returns int | 40 | * @returns int |
41 | */ | 41 | */ |
42 | getMediaIndexByTime = function (playlist, time) { | 42 | getMediaIndexByTime = function(playlist, time) { |
43 | var index, counter, timeRanges, currentSegmentRange; | 43 | var index, counter, timeRanges, currentSegmentRange; |
44 | 44 | ||
45 | timeRanges = []; | 45 | timeRanges = []; |
... | @@ -59,7 +59,7 @@ var | ... | @@ -59,7 +59,7 @@ var |
59 | return -1; | 59 | return -1; |
60 | 60 | ||
61 | }, | 61 | }, |
62 | getPtsByTime = function (segmentParser, time) { | 62 | getPtsByTime = function(segmentParser, time) { |
63 | var index = 0; | 63 | var index = 0; |
64 | 64 | ||
65 | for (index; index<segmentParser.getTags().length; index++) { | 65 | for (index; index<segmentParser.getTags().length; index++) { |
... | @@ -74,6 +74,23 @@ var | ... | @@ -74,6 +74,23 @@ var |
74 | }, | 74 | }, |
75 | 75 | ||
76 | /** | 76 | /** |
77 | * Calculate the total duration for a playlist based on segment metadata. | ||
78 | * @param playlist {object} a media playlist object | ||
79 | * @return {number} the currently known duration, in seconds | ||
80 | */ | ||
81 | totalDuration = function(playlist) { | ||
82 | var | ||
83 | duration = 0, | ||
84 | i = playlist.segments.length, | ||
85 | segment; | ||
86 | while (i--) { | ||
87 | segment = playlist.segments[i]; | ||
88 | duration += segment.duration || playlist.targetDuration || 0; | ||
89 | } | ||
90 | return duration; | ||
91 | }, | ||
92 | |||
93 | /** | ||
77 | * Constructs a new URI by interpreting a path relative to another | 94 | * Constructs a new URI by interpreting a path relative to another |
78 | * URI. | 95 | * URI. |
79 | * @param basePath {string} a relative or absolute URI | 96 | * @param basePath {string} a relative or absolute URI |
... | @@ -254,6 +271,8 @@ var | ... | @@ -254,6 +271,8 @@ var |
254 | player.duration(parser.manifest.totalDuration); | 271 | player.duration(parser.manifest.totalDuration); |
255 | // Notify the flash layer | 272 | // Notify the flash layer |
256 | //player.el().querySelector('.vjs-tech').vjs_setProperty('duration',parser.manifest.totalDuration); | 273 | //player.el().querySelector('.vjs-tech').vjs_setProperty('duration',parser.manifest.totalDuration); |
274 | } else { | ||
275 | player.duration(totalDuration(parser.manifest)); | ||
257 | } | 276 | } |
258 | player.trigger('loadedmanifest'); | 277 | player.trigger('loadedmanifest'); |
259 | player.trigger('loadedmetadata'); | 278 | player.trigger('loadedmetadata'); |
... | @@ -266,9 +285,11 @@ var | ... | @@ -266,9 +285,11 @@ var |
266 | downloadPlaylist(resolveUrl(srcUrl, playlist.uri)); | 285 | downloadPlaylist(resolveUrl(srcUrl, playlist.uri)); |
267 | } else { | 286 | } else { |
268 | player.hls.media = playlist; | 287 | player.hls.media = playlist; |
269 | if (parser.manifest.totalDuration) { | 288 | if (player.hls.media.totalDuration) { |
270 | // update the duration | 289 | // update the duration |
271 | player.duration(parser.manifest.totalDuration); | 290 | player.duration(player.hls.media.totalDuration); |
291 | } else { | ||
292 | player.duration(totalDuration(player.hls.media)); | ||
272 | } | 293 | } |
273 | } | 294 | } |
274 | 295 | ... | ... |
... | @@ -20,6 +20,5 @@ | ... | @@ -20,6 +20,5 @@ |
20 | "uri": "/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts" | 20 | "uri": "/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts" |
21 | } | 21 | } |
22 | ], | 22 | ], |
23 | "targetDuration": 8, | 23 | "targetDuration": 8 |
24 | "totalDuration": 24.32 | ||
25 | } | 24 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -28,6 +28,5 @@ | ... | @@ -28,6 +28,5 @@ |
28 | "uri": "/test/ts-files/zencoder/haze/Haze_Mantel_President_encoded_1200-00006.ts" | 28 | "uri": "/test/ts-files/zencoder/haze/Haze_Mantel_President_encoded_1200-00006.ts" |
29 | } | 29 | } |
30 | ], | 30 | ], |
31 | "targetDuration": 10, | 31 | "targetDuration": 10 |
32 | "totalDuration": 58 | ||
33 | } | 32 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -28,6 +28,5 @@ | ... | @@ -28,6 +28,5 @@ |
28 | "uri": "/test/ts-files/zencoder/haze/Haze_Mantel_President_encoded_1200-00006.ts" | 28 | "uri": "/test/ts-files/zencoder/haze/Haze_Mantel_President_encoded_1200-00006.ts" |
29 | } | 29 | } |
30 | ], | 30 | ], |
31 | "targetDuration": 10, | 31 | "targetDuration": 10 |
32 | "totalDuration": 58 | ||
33 | } | 32 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -8,6 +8,5 @@ | ... | @@ -8,6 +8,5 @@ |
8 | "uri": "/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts" | 8 | "uri": "/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts" |
9 | } | 9 | } |
10 | ], | 10 | ], |
11 | "targetDuration": 8, | 11 | "targetDuration": 8 |
12 | "totalDuration": 6.64 | ||
13 | } | 12 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -20,6 +20,5 @@ | ... | @@ -20,6 +20,5 @@ |
20 | "uri": "/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts" | 20 | "uri": "/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts" |
21 | } | 21 | } |
22 | ], | 22 | ], |
23 | "targetDuration": 8, | 23 | "targetDuration": 8 |
24 | "totalDuration": 24.32 | ||
25 | } | 24 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -28,6 +28,5 @@ | ... | @@ -28,6 +28,5 @@ |
28 | "uri": "/test/ts-files/zencoder/haze/Haze_Mantel_President_encoded_1200-00006.ts" | 28 | "uri": "/test/ts-files/zencoder/haze/Haze_Mantel_President_encoded_1200-00006.ts" |
29 | } | 29 | } |
30 | ], | 30 | ], |
31 | "targetDuration": 10, | 31 | "targetDuration": 10 |
32 | "totalDuration": 58 | ||
33 | } | 32 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
1 | { | ||
2 | "allowCache": true, | ||
3 | "mediaSequence": 0, | ||
4 | "playlistType": "VOD", | ||
5 | "segments": [ | ||
6 | { | ||
7 | "duration": 6.64, | ||
8 | "uri": "/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts" | ||
9 | }, | ||
10 | { | ||
11 | "uri": "/test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts" | ||
12 | }, | ||
13 | { | ||
14 | "uri": "/test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts" | ||
15 | } | ||
16 | ], | ||
17 | "targetDuration": 8 | ||
18 | } | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | #EXTM3U | ||
2 | #EXT-X-PLAYLIST-TYPE:VOD | ||
3 | #EXT-X-MEDIA-SEQUENCE:0 | ||
4 | #EXT-X-ALLOW-CACHE:YES | ||
5 | #EXT-X-TARGETDURATION:8 | ||
6 | #EXTINF:6.640,{} | ||
7 | /test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts | ||
8 | /test/ts-files/tvy7/56be1cef869a1c0cc8e38864ad1add17d187f051-hi720.ts | ||
9 | /test/ts-files/tvy7/549c8c77f55f049741a06596e5c1e01dacaa46d0-hi720.ts |
... | @@ -24,6 +24,5 @@ | ... | @@ -24,6 +24,5 @@ |
24 | "uri": "/test/ts-files/zencoder/gogo/00005.ts" | 24 | "uri": "/test/ts-files/zencoder/gogo/00005.ts" |
25 | } | 25 | } |
26 | ], | 26 | ], |
27 | "targetDuration": 10, | 27 | "targetDuration": 10 |
28 | "totalDuration": 30 | ||
29 | } | 28 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -8,6 +8,5 @@ | ... | @@ -8,6 +8,5 @@ |
8 | "uri": "/test/ts-files/zencoder/gogo/00001.ts" | 8 | "uri": "/test/ts-files/zencoder/gogo/00001.ts" |
9 | } | 9 | } |
10 | ], | 10 | ], |
11 | "targetDuration": 10, | 11 | "targetDuration": 10 |
12 | "totalDuration": 10 | ||
13 | } | 12 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -20,6 +20,5 @@ | ... | @@ -20,6 +20,5 @@ |
20 | "uri": "/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts" | 20 | "uri": "/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts" |
21 | } | 21 | } |
22 | ], | 22 | ], |
23 | "targetDuration": 8, | 23 | "targetDuration": 8 |
24 | "totalDuration": 24.32 | ||
25 | } | 24 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -20,6 +20,5 @@ | ... | @@ -20,6 +20,5 @@ |
20 | "uri": "/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts" | 20 | "uri": "/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts" |
21 | } | 21 | } |
22 | ], | 22 | ], |
23 | "targetDuration": 8, | 23 | "targetDuration": 8 |
24 | "totalDuration": 24.32 | ||
25 | } | 24 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -17,6 +17,5 @@ | ... | @@ -17,6 +17,5 @@ |
17 | "uri": "/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts" | 17 | "uri": "/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts" |
18 | } | 18 | } |
19 | ], | 19 | ], |
20 | "targetDuration": 8, | 20 | "targetDuration": 8 |
21 | "totalDuration": 30.64 | ||
22 | } | 21 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -20,6 +20,5 @@ | ... | @@ -20,6 +20,5 @@ |
20 | "uri": "/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts" | 20 | "uri": "/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts" |
21 | } | 21 | } |
22 | ], | 22 | ], |
23 | "targetDuration": 8, | 23 | "targetDuration": 8 |
24 | "totalDuration": 24.32 | ||
25 | } | 24 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -8,6 +8,5 @@ | ... | @@ -8,6 +8,5 @@ |
8 | "uri": "/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts" | 8 | "uri": "/test/ts-files/tvy7/8a5e2822668b5370f4eb1438b2564fb7ab12ffe1-hi720.ts" |
9 | } | 9 | } |
10 | ], | 10 | ], |
11 | "targetDuration": 8, | 11 | "targetDuration": 8 |
12 | "totalDuration": 6.64 | ||
13 | } | 12 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -20,6 +20,5 @@ | ... | @@ -20,6 +20,5 @@ |
20 | "uri": "/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts" | 20 | "uri": "/test/ts-files/tvy7/6cfa378684ffeb1c455a64dae6c103290a1f53d4-hi720.ts" |
21 | } | 21 | } |
22 | ], | 22 | ], |
23 | "targetDuration": 8, | 23 | "targetDuration": 8 |
24 | "totalDuration": 24.32 | ||
25 | } | 24 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -124,6 +124,23 @@ test('sets the duration if one is available on the playlist', function() { | ... | @@ -124,6 +124,23 @@ test('sets the duration if one is available on the playlist', function() { |
124 | strictEqual(1, calls, 'duration is set'); | 124 | strictEqual(1, calls, 'duration is set'); |
125 | }); | 125 | }); |
126 | 126 | ||
127 | test('calculates the duration if needed', function() { | ||
128 | var durations = []; | ||
129 | player.duration = function(duration) { | ||
130 | if (duration === undefined) { | ||
131 | return 0; | ||
132 | } | ||
133 | durations.push(duration); | ||
134 | }; | ||
135 | player.hls('manifest/liveMissingSegmentDuration.m3u8'); | ||
136 | videojs.mediaSources[player.currentSrc()].trigger({ | ||
137 | type: 'sourceopen' | ||
138 | }); | ||
139 | |||
140 | strictEqual(durations.length, 1, 'duration is set'); | ||
141 | strictEqual(durations[0], 6.64 + (2 * 8), 'duration is calculated'); | ||
142 | }); | ||
143 | |||
127 | test('starts downloading a segment on loadedmetadata', function() { | 144 | test('starts downloading a segment on loadedmetadata', function() { |
128 | player.hls('manifest/media.m3u8'); | 145 | player.hls('manifest/media.m3u8'); |
129 | player.buffered = function() { | 146 | player.buffered = function() { |
... | @@ -226,6 +243,32 @@ test('selects a playlist after segment downloads', function() { | ... | @@ -226,6 +243,32 @@ test('selects a playlist after segment downloads', function() { |
226 | strictEqual(calls, 2, 'selects after additional segments'); | 243 | strictEqual(calls, 2, 'selects after additional segments'); |
227 | }); | 244 | }); |
228 | 245 | ||
246 | test('updates the duration after switching playlists', function() { | ||
247 | var | ||
248 | calls = 0, | ||
249 | selectedPlaylist = false; | ||
250 | player.hls('manifest/master.m3u8'); | ||
251 | player.hls.selectPlaylist = function() { | ||
252 | selectPlaylist = true; | ||
253 | return player.hls.master.playlists[1]; | ||
254 | }; | ||
255 | player.duration = function(duration) { | ||
256 | if (duration === undefined) { | ||
257 | return 0; | ||
258 | } | ||
259 | // only track calls that occur after the playlist has been switched | ||
260 | if (player.hls.media === player.hls.master.playlists[1]) { | ||
261 | calls++; | ||
262 | } | ||
263 | }; | ||
264 | videojs.mediaSources[player.currentSrc()].trigger({ | ||
265 | type: 'sourceopen' | ||
266 | }); | ||
267 | |||
268 | ok(selectPlaylist, 'selected playlist'); | ||
269 | strictEqual(calls, 1, 'updates the duration'); | ||
270 | }); | ||
271 | |||
229 | test('downloads additional playlists if required', function() { | 272 | test('downloads additional playlists if required', function() { |
230 | var | 273 | var |
231 | called = false, | 274 | called = false, | ... | ... |
-
Please register or sign in to post a comment