8e72fc98 by Steve Heffernan

Moved currentTime functions and broke up large fillBuffer function

1 parent b858aa92
...@@ -27,44 +27,9 @@ videojs.Hls = videojs.Flash.extend({ ...@@ -27,44 +27,9 @@ videojs.Hls = videojs.Flash.extend({
27 options.source = source; 27 options.source = source;
28 this.bytesReceived = 0; 28 this.bytesReceived = 0;
29 29
30 // TODO: After video.js#1347 is pulled in move these to the prototype 30 // TODO: After video.js#1347 is pulled in remove these lines
31 this.currentTime = function() { 31 this.currentTime = videojs.Hls.prototype.currentTime;
32 if (this.lastSeekedTime_) { 32 this.setCurrentTime = videojs.Hls.prototype.setCurrentTime;
33 return this.lastSeekedTime_;
34 }
35 // currentTime is zero while the tech is initializing
36 if (!this.el() || !this.el().vjs_getProperty) {
37 return 0;
38 }
39 return this.el().vjs_getProperty('currentTime');
40 };
41 this.setCurrentTime = function(currentTime) {
42 if (!(this.playlists && this.playlists.media())) {
43 // return immediately if the metadata is not ready yet
44 return 0;
45 }
46
47 // save the seek target so currentTime can report it correctly
48 // while the seek is pending
49 this.lastSeekedTime_ = currentTime;
50
51 // determine the requested segment
52 this.mediaIndex = videojs.Hls.getMediaIndexByTime(this.playlists.media(), currentTime);
53
54 // abort any segments still being decoded
55 this.sourceBuffer.abort();
56
57 // cancel outstanding requests and buffer appends
58 if (this.segmentXhr_) {
59 this.segmentXhr_.abort();
60 }
61
62 // clear out any buffered segments
63 this.segmentBuffer_ = [];
64
65 // begin filling the buffer at the new position
66 this.fillBuffer(currentTime * 1000);
67 };
68 33
69 videojs.Hls.prototype.src.call(this, options.source && options.source.src); 34 videojs.Hls.prototype.src.call(this, options.source && options.source.src);
70 } 35 }
...@@ -78,7 +43,7 @@ videojs.Hls.GOAL_BUFFER_LENGTH = 30; ...@@ -78,7 +43,7 @@ videojs.Hls.GOAL_BUFFER_LENGTH = 30;
78 43
79 videojs.Hls.prototype.src = function(src) { 44 videojs.Hls.prototype.src = function(src) {
80 var 45 var
81 self = this, 46 tech = this,
82 mediaSource, 47 mediaSource,
83 source; 48 source;
84 49
...@@ -101,10 +66,10 @@ videojs.Hls.prototype.src = function(src) { ...@@ -101,10 +66,10 @@ videojs.Hls.prototype.src = function(src) {
101 this.player().ready(function() { 66 this.player().ready(function() {
102 // do nothing if the tech has been disposed already 67 // do nothing if the tech has been disposed already
103 // this can occur if someone sets the src in player.ready(), for instance 68 // this can occur if someone sets the src in player.ready(), for instance
104 if (!self.el()) { 69 if (!tech.el()) {
105 return; 70 return;
106 } 71 }
107 self.el().vjs_src(source.src); 72 tech.el().vjs_src(source.src);
108 }); 73 });
109 } 74 }
110 }; 75 };
...@@ -171,6 +136,45 @@ videojs.Hls.prototype.play = function() { ...@@ -171,6 +136,45 @@ videojs.Hls.prototype.play = function() {
171 return videojs.Flash.prototype.play.apply(this, arguments); 136 return videojs.Flash.prototype.play.apply(this, arguments);
172 }; 137 };
173 138
139 videojs.Hls.prototype.currentTime = function() {
140 if (this.lastSeekedTime_) {
141 return this.lastSeekedTime_;
142 }
143 // currentTime is zero while the tech is initializing
144 if (!this.el() || !this.el().vjs_getProperty) {
145 return 0;
146 }
147 return this.el().vjs_getProperty('currentTime');
148 };
149
150 videojs.Hls.prototype.setCurrentTime = function(currentTime) {
151 if (!(this.playlists && this.playlists.media())) {
152 // return immediately if the metadata is not ready yet
153 return 0;
154 }
155
156 // save the seek target so currentTime can report it correctly
157 // while the seek is pending
158 this.lastSeekedTime_ = currentTime;
159
160 // determine the requested segment
161 this.mediaIndex = videojs.Hls.getMediaIndexByTime(this.playlists.media(), currentTime);
162
163 // abort any segments still being decoded
164 this.sourceBuffer.abort();
165
166 // cancel outstanding requests and buffer appends
167 if (this.segmentXhr_) {
168 this.segmentXhr_.abort();
169 }
170
171 // clear out any buffered segments
172 this.segmentBuffer_ = [];
173
174 // begin filling the buffer at the new position
175 this.fillBuffer(currentTime * 1000);
176 };
177
174 videojs.Hls.prototype.duration = function() { 178 videojs.Hls.prototype.duration = function() {
175 var playlists = this.playlists; 179 var playlists = this.playlists;
176 if (playlists) { 180 if (playlists) {
...@@ -289,14 +293,11 @@ videojs.Hls.prototype.selectPlaylist = function () { ...@@ -289,14 +293,11 @@ videojs.Hls.prototype.selectPlaylist = function () {
289 */ 293 */
290 videojs.Hls.prototype.fillBuffer = function(offset) { 294 videojs.Hls.prototype.fillBuffer = function(offset) {
291 var 295 var
292 self = this,
293 player = this.player(), 296 player = this.player(),
294 settings = player.options().hls || {},
295 buffered = player.buffered(), 297 buffered = player.buffered(),
296 bufferedTime = 0, 298 bufferedTime = 0,
297 segment, 299 segment,
298 segmentUri, 300 segmentUri;
299 startTime;
300 301
301 // if there is a request already in flight, do nothing 302 // if there is a request already in flight, do nothing
302 if (this.segmentXhr_) { 303 if (this.segmentXhr_) {
...@@ -322,8 +323,7 @@ videojs.Hls.prototype.fillBuffer = function(offset) { ...@@ -322,8 +323,7 @@ videojs.Hls.prototype.fillBuffer = function(offset) {
322 323
323 // if there is plenty of content in the buffer and we're not 324 // if there is plenty of content in the buffer and we're not
324 // seeking, relax for awhile 325 // seeking, relax for awhile
325 if (typeof offset !== 'number' && 326 if (typeof offset !== 'number' && bufferedTime >= videojs.Hls.GOAL_BUFFER_LENGTH) {
326 bufferedTime >= videojs.Hls.GOAL_BUFFER_LENGTH) {
327 return; 327 return;
328 } 328 }
329 329
...@@ -331,10 +331,17 @@ videojs.Hls.prototype.fillBuffer = function(offset) { ...@@ -331,10 +331,17 @@ videojs.Hls.prototype.fillBuffer = function(offset) {
331 if (this.playlists.media().uri === this.src_) { 331 if (this.playlists.media().uri === this.src_) {
332 segmentUri = resolveUrl(this.src_, segment.uri); 332 segmentUri = resolveUrl(this.src_, segment.uri);
333 } else { 333 } else {
334 segmentUri = resolveUrl(resolveUrl(this.src_, this.playlists.media().uri || ''), 334 segmentUri = resolveUrl(resolveUrl(this.src_, this.playlists.media().uri || ''), segment.uri);
335 segment.uri);
336 } 335 }
337 336
337 this.loadSegment(segmentUri, offset);
338 };
339
340 videojs.Hls.prototype.loadSegment = function(segmentUri, offset) {
341 var
342 tech = this,
343 player = this.player(),
344 settings = player.options().hls || {},
338 startTime = +new Date(); 345 startTime = +new Date();
339 346
340 // request the next segment 347 // request the next segment
...@@ -346,23 +353,23 @@ videojs.Hls.prototype.fillBuffer = function(offset) { ...@@ -346,23 +353,23 @@ videojs.Hls.prototype.fillBuffer = function(offset) {
346 var tags; 353 var tags;
347 354
348 // the segment request is no longer outstanding 355 // the segment request is no longer outstanding
349 self.segmentXhr_ = null; 356 tech.segmentXhr_ = null;
350 357
351 if (error) { 358 if (error) {
352 // if a segment request times out, we may have better luck with another playlist 359 // if a segment request times out, we may have better luck with another playlist
353 if (error === 'timeout') { 360 if (error === 'timeout') {
354 self.bandwidth = 1; 361 tech.bandwidth = 1;
355 return self.playlists.media(self.selectPlaylist()); 362 return tech.playlists.media(tech.selectPlaylist());
356 } 363 }
357 // otherwise, try jumping ahead to the next segment 364 // otherwise, try jumping ahead to the next segment
358 self.error = { 365 tech.error = {
359 status: this.status, 366 status: this.status,
360 message: 'HLS segment request error at URL: ' + url, 367 message: 'HLS segment request error at URL: ' + url,
361 code: (this.status >= 500) ? 4 : 2 368 code: (this.status >= 500) ? 4 : 2
362 }; 369 };
363 370
364 // try moving on to the next segment 371 // try moving on to the next segment
365 self.mediaIndex++; 372 tech.mediaIndex++;
366 return; 373 return;
367 } 374 }
368 375
...@@ -372,35 +379,35 @@ videojs.Hls.prototype.fillBuffer = function(offset) { ...@@ -372,35 +379,35 @@ videojs.Hls.prototype.fillBuffer = function(offset) {
372 } 379 }
373 380
374 // calculate the download bandwidth 381 // calculate the download bandwidth
375 self.segmentXhrTime = (+new Date()) - startTime; 382 tech.segmentXhrTime = (+new Date()) - startTime;
376 self.bandwidth = (this.response.byteLength / player.hls.segmentXhrTime) * 8 * 1000; 383 tech.bandwidth = (this.response.byteLength / tech.segmentXhrTime) * 8 * 1000;
377 self.bytesReceived += this.response.byteLength; 384 tech.bytesReceived += this.response.byteLength;
378 385
379 // transmux the segment data from MP2T to FLV 386 // transmux the segment data from MP2T to FLV
380 self.segmentParser_.parseSegmentBinaryData(new Uint8Array(this.response)); 387 tech.segmentParser_.parseSegmentBinaryData(new Uint8Array(this.response));
381 self.segmentParser_.flushTags(); 388 tech.segmentParser_.flushTags();
382 389
383 // package up all the work to append the segment 390 // package up all the work to append the segment
384 // if the segment is the start of a timestamp discontinuity, 391 // if the segment is the start of a timestamp discontinuity,
385 // we have to wait until the sourcebuffer is empty before 392 // we have to wait until the sourcebuffer is empty before
386 // aborting the source buffer processing 393 // aborting the source buffer processing
387 tags = []; 394 tags = [];
388 while (self.segmentParser_.tagsAvailable()) { 395 while (tech.segmentParser_.tagsAvailable()) {
389 tags.push(self.segmentParser_.getNextTag()); 396 tags.push(tech.segmentParser_.getNextTag());
390 } 397 }
391 self.segmentBuffer_.push({ 398 tech.segmentBuffer_.push({
392 mediaIndex: self.mediaIndex, 399 mediaIndex: tech.mediaIndex,
393 playlist: self.playlists.media(), 400 playlist: tech.playlists.media(),
394 offset: offset, 401 offset: offset,
395 tags: tags 402 tags: tags
396 }); 403 });
397 self.drainBuffer(); 404 tech.drainBuffer();
398 405
399 self.mediaIndex++; 406 tech.mediaIndex++;
400 407
401 // figure out what stream the next segment should be downloaded from 408 // figure out what stream the next segment should be downloaded from
402 // with the updated bandwidth information 409 // with the updated bandwidth information
403 self.playlists.media(self.selectPlaylist()); 410 tech.playlists.media(tech.selectPlaylist());
404 }); 411 });
405 }; 412 };
406 413
......