Merge pull request #229 from videojs/live-start-time
Live start time tweaks
Showing
3 changed files
with
65 additions
and
8 deletions
... | @@ -39,7 +39,7 @@ | ... | @@ -39,7 +39,7 @@ |
39 | "karma-sauce-launcher": "~0.1.8", | 39 | "karma-sauce-launcher": "~0.1.8", |
40 | "qunitjs": "^1.15.0", | 40 | "qunitjs": "^1.15.0", |
41 | "sinon": "1.10.2", | 41 | "sinon": "1.10.2", |
42 | "video.js": "^4.9.0" | 42 | "video.js": "^4.12.0" |
43 | }, | 43 | }, |
44 | "dependencies": { | 44 | "dependencies": { |
45 | "pkcs7": "^0.2.2", | 45 | "pkcs7": "^0.2.2", | ... | ... |
... | @@ -164,6 +164,16 @@ videojs.Hls.prototype.src = function(src) { | ... | @@ -164,6 +164,16 @@ videojs.Hls.prototype.src = function(src) { |
164 | }); | 164 | }); |
165 | } | 165 | } |
166 | 166 | ||
167 | // Start live playlists 30 seconds before the current time | ||
168 | // This is done using the old playlist because of a race condition | ||
169 | // where the playlist selected below may not be loaded quickly | ||
170 | // enough to have its segments available for review. When we receive | ||
171 | // a loadedplaylist event, we will call translateMediaIndex and | ||
172 | // maintain our position at the live point. | ||
173 | if (this.duration() === Infinity && this.mediaIndex === 0) { | ||
174 | this.mediaIndex = videojs.Hls.getMediaIndexForLive_(oldMediaPlaylist); | ||
175 | } | ||
176 | |||
167 | selectedPlaylist = this.selectPlaylist(); | 177 | selectedPlaylist = this.selectPlaylist(); |
168 | oldBitrate = oldMediaPlaylist.attributes && | 178 | oldBitrate = oldMediaPlaylist.attributes && |
169 | oldMediaPlaylist.attributes.BANDWIDTH || 0; | 179 | oldMediaPlaylist.attributes.BANDWIDTH || 0; |
... | @@ -179,11 +189,6 @@ videojs.Hls.prototype.src = function(src) { | ... | @@ -179,11 +189,6 @@ videojs.Hls.prototype.src = function(src) { |
179 | segmentDlTime = Infinity; | 189 | segmentDlTime = Infinity; |
180 | } | 190 | } |
181 | 191 | ||
182 | // start live playlists 30 seconds before the current time | ||
183 | if (this.duration() === Infinity && this.mediaIndex === 0 && selectedPlaylist.segments) { | ||
184 | this.mediaIndex = videojs.Hls.setMediaIndexForLive(selectedPlaylist); | ||
185 | } | ||
186 | |||
187 | // this threshold is to account for having a high latency on the manifest | 192 | // this threshold is to account for having a high latency on the manifest |
188 | // request which is a somewhat small file. | 193 | // request which is a somewhat small file. |
189 | threshold = 10; | 194 | threshold = 10; |
... | @@ -239,7 +244,14 @@ videojs.Hls.prototype.src = function(src) { | ... | @@ -239,7 +244,14 @@ videojs.Hls.prototype.src = function(src) { |
239 | }); | 244 | }); |
240 | }; | 245 | }; |
241 | 246 | ||
242 | videojs.Hls.setMediaIndexForLive = function(selectedPlaylist) { | 247 | /* Returns the media index for the live point in the current playlist, and updates |
248 | the current time to go along with it. | ||
249 | */ | ||
250 | videojs.Hls.getMediaIndexForLive_ = function(selectedPlaylist) { | ||
251 | if (!selectedPlaylist.segments) { | ||
252 | return 0; | ||
253 | } | ||
254 | |||
243 | var tailIterator = selectedPlaylist.segments.length, | 255 | var tailIterator = selectedPlaylist.segments.length, |
244 | tailDuration = 0, | 256 | tailDuration = 0, |
245 | targetTail = (selectedPlaylist.targetDuration || 10) * 3; | 257 | targetTail = (selectedPlaylist.targetDuration || 10) * 3; |
... | @@ -279,6 +291,11 @@ videojs.Hls.prototype.play = function() { | ... | @@ -279,6 +291,11 @@ videojs.Hls.prototype.play = function() { |
279 | this.mediaIndex = 0; | 291 | this.mediaIndex = 0; |
280 | } | 292 | } |
281 | 293 | ||
294 | if (this.duration() === Infinity && this.playlists.media() && !this.player().hasClass('vjs-has-started')) { | ||
295 | this.mediaIndex = videojs.Hls.getMediaIndexForLive_(this.playlists.media()); | ||
296 | this.setCurrentTime(this.getCurrentTimeByMediaIndex_(this.playlists.media(), this.mediaIndex)); | ||
297 | } | ||
298 | |||
282 | // delegate back to the Flash implementation | 299 | // delegate back to the Flash implementation |
283 | return videojs.Flash.prototype.play.apply(this, arguments); | 300 | return videojs.Flash.prototype.play.apply(this, arguments); |
284 | }; | 301 | }; |
... | @@ -936,7 +953,7 @@ videojs.Hls.translateMediaIndex = function(mediaIndex, original, update) { | ... | @@ -936,7 +953,7 @@ videojs.Hls.translateMediaIndex = function(mediaIndex, original, update) { |
936 | 953 | ||
937 | if (translatedMediaIndex >= update.segments.length || translatedMediaIndex < 0) { | 954 | if (translatedMediaIndex >= update.segments.length || translatedMediaIndex < 0) { |
938 | // recalculate the live point if the streams are too far out of sync | 955 | // recalculate the live point if the streams are too far out of sync |
939 | return videojs.Hls.setMediaIndexForLive(update) + 1; | 956 | return videojs.Hls.getMediaIndexForLive_(update) + 1; |
940 | } | 957 | } |
941 | 958 | ||
942 | // sync on media sequence | 959 | // sync on media sequence |
... | @@ -974,6 +991,29 @@ videojs.Hls.getMediaIndexByTime = function(playlist, time) { | ... | @@ -974,6 +991,29 @@ videojs.Hls.getMediaIndexByTime = function(playlist, time) { |
974 | }; | 991 | }; |
975 | 992 | ||
976 | /** | 993 | /** |
994 | * Determine the current time in seconds in one playlist by a media index. This | ||
995 | * function iterates through the segments of a playlist up to the specified index | ||
996 | * and then returns the time up to that point. | ||
997 | * | ||
998 | * @param playlist {object} The playlist of the segments being searched. | ||
999 | * @param mediaIndex {number} The index of the target segment in the playlist. | ||
1000 | * @returns {number} The current time to that point, or 0 if none appropriate. | ||
1001 | */ | ||
1002 | videojs.Hls.prototype.getCurrentTimeByMediaIndex_ = function(playlist, mediaIndex) { | ||
1003 | var index, time = 0; | ||
1004 | |||
1005 | if (!playlist.segments || mediaIndex === 0) { | ||
1006 | return 0; | ||
1007 | } | ||
1008 | |||
1009 | for (index = 0; index < mediaIndex; index++) { | ||
1010 | time += playlist.segments[index].duration; | ||
1011 | } | ||
1012 | |||
1013 | return time; | ||
1014 | }; | ||
1015 | |||
1016 | /** | ||
977 | * A comparator function to sort two playlist object by bandwidth. | 1017 | * A comparator function to sort two playlist object by bandwidth. |
978 | * @param left {object} a media playlist object | 1018 | * @param left {object} a media playlist object |
979 | * @param right {object} a media playlist object | 1019 | * @param right {object} a media playlist object | ... | ... |
... | @@ -1249,6 +1249,22 @@ test('live playlist starts 30s before live', function() { | ... | @@ -1249,6 +1249,22 @@ test('live playlist starts 30s before live', function() { |
1249 | strictEqual(player.hls.mediaIndex, 6, 'mediaIndex is updated after the reload'); | 1249 | strictEqual(player.hls.mediaIndex, 6, 'mediaIndex is updated after the reload'); |
1250 | }); | 1250 | }); |
1251 | 1251 | ||
1252 | test('live playlist starts with correct currentTime value', function() { | ||
1253 | player.src({ | ||
1254 | src: 'http://example.com/manifest/liveStart30sBefore.m3u8', | ||
1255 | type: 'application/vnd.apple.mpegurl' | ||
1256 | }); | ||
1257 | openMediaSource(player); | ||
1258 | |||
1259 | standardXHRResponse(requests[0]); | ||
1260 | |||
1261 | player.hls.playlists.trigger('loadedmetadata'); | ||
1262 | |||
1263 | player.hls.play(); | ||
1264 | |||
1265 | strictEqual(player.currentTime(), 70, 'currentTime is updated at playback'); | ||
1266 | }); | ||
1267 | |||
1252 | test('mediaIndex is zero before the first segment loads', function() { | 1268 | test('mediaIndex is zero before the first segment loads', function() { |
1253 | window.manifests['first-seg-load'] = | 1269 | window.manifests['first-seg-load'] = |
1254 | '#EXTM3U\n' + | 1270 | '#EXTM3U\n' + |
... | @@ -1720,6 +1736,7 @@ test('calling play() at the end of a video resets the media index', function() { | ... | @@ -1720,6 +1736,7 @@ test('calling play() at the end of a video resets the media index', function() { |
1720 | player.hls.ended = function() { | 1736 | player.hls.ended = function() { |
1721 | return true; | 1737 | return true; |
1722 | }; | 1738 | }; |
1739 | |||
1723 | player.play(); | 1740 | player.play(); |
1724 | strictEqual(player.hls.mediaIndex, 0, 'index is 1 after the first segment'); | 1741 | strictEqual(player.hls.mediaIndex, 0, 'index is 1 after the first segment'); |
1725 | }); | 1742 | }); | ... | ... |
-
Please register or sign in to post a comment