56919c5f by David LaPalomento

Merge pull request #439 from videojs/fix-fetcher

Minor fixes to fetcher
2 parents 958f2b8c 7c6736ca
...@@ -141,9 +141,7 @@ ...@@ -141,9 +141,7 @@
141 // https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-6.3.3 141 // https://tools.ietf.org/html/draft-pantos-http-live-streaming-16#section-6.3.3
142 start = intervalDuration(playlist, playlist.mediaSequence); 142 start = intervalDuration(playlist, playlist.mediaSequence);
143 end = intervalDuration(playlist, 143 end = intervalDuration(playlist,
144 playlist.mediaSequence + playlist.segments.length); 144 playlist.mediaSequence + Math.max(0, playlist.segments.length - 3));
145 end -= (playlist.targetDuration || DEFAULT_TARGET_DURATION) * 3;
146 end = Math.max(0, end);
147 return videojs.createTimeRange(start, end); 145 return videojs.createTimeRange(start, end);
148 }; 146 };
149 147
......
...@@ -9,14 +9,15 @@ ...@@ -9,14 +9,15 @@
9 var 9 var
10 // a fudge factor to apply to advertised playlist bitrates to account for 10 // a fudge factor to apply to advertised playlist bitrates to account for
11 // temporary flucations in client bandwidth 11 // temporary flucations in client bandwidth
12 bandwidthVariance = 1.1, 12 bandwidthVariance = 1.2,
13 Component = videojs.getComponent('Component'), 13 Component = videojs.getComponent('Component'),
14 14
15 // the amount of time to wait between checking the state of the buffer 15 // the amount of time to wait between checking the state of the buffer
16 bufferCheckInterval = 500, 16 bufferCheckInterval = 500,
17 17
18 keyFailed, 18 keyFailed,
19 resolveUrl; 19 resolveUrl,
20 TIME_FUDGE_FACTOR = 1 / 60;
20 21
21 // returns true if a key has failed to download within a certain amount of retries 22 // returns true if a key has failed to download within a certain amount of retries
22 keyFailed = function(key) { 23 keyFailed = function(key) {
...@@ -396,72 +397,7 @@ videojs.HlsHandler.prototype.setupSourceBuffer_ = function() { ...@@ -396,72 +397,7 @@ videojs.HlsHandler.prototype.setupSourceBuffer_ = function() {
396 397
397 // transition the sourcebuffer to the ended state if we've hit the end of 398 // transition the sourcebuffer to the ended state if we've hit the end of
398 // the playlist 399 // the playlist
399 this.sourceBuffer.addEventListener('updateend', function() { 400 this.sourceBuffer.addEventListener('updateend', this.updateEndHandler_.bind(this));
400 var
401 segmentInfo = this.pendingSegment_,
402 segment,
403 segments,
404 playlist,
405 currentMediaIndex,
406 currentBuffered,
407 timelineUpdates;
408
409 this.pendingSegment_ = null;
410
411 // stop here if the update errored or was aborted
412 if (!segmentInfo) {
413 return;
414 }
415
416 playlist = this.playlists.media();
417 segments = playlist.segments;
418 currentMediaIndex = segmentInfo.mediaIndex + (segmentInfo.mediaSequence - playlist.mediaSequence);
419 currentBuffered = this.findCurrentBuffered_();
420
421 // if we switched renditions don't try to add segment timeline
422 // information to the playlist
423 if (segmentInfo.playlist.uri !== this.playlists.media().uri) {
424 return this.fillBuffer();
425 }
426
427 // annotate the segment with any start and end time information
428 // added by the media processing
429 segment = playlist.segments[currentMediaIndex];
430
431 timelineUpdates = videojs.Hls.bufferedAdditions_(segmentInfo.buffered,
432 this.tech_.buffered());
433
434 timelineUpdates.forEach(function (update) {
435 if (segment) {
436 if (update.end !== undefined) {
437 segment.end = update.end;
438 }
439 }
440 });
441
442 // if we've buffered to the end of the video, let the MediaSource know
443 if (this.playlists.media().endList &&
444 currentBuffered.length &&
445 segments[segments.length - 1].end <= currentBuffered.end(0) &&
446 this.mediaSource.readyState === 'open') {
447 this.mediaSource.endOfStream();
448 return;
449 }
450
451 if (timelineUpdates.length) {
452 this.updateDuration(playlist);
453 // check if it's time to download the next segment
454 this.fillBuffer();
455 return;
456 }
457
458 // the last segment append must have been entirely in the
459 // already buffered time ranges. just buffer forward until we
460 // find a segment that adds to the buffered time ranges and
461 // improves subsequent media index calculations.
462 this.fillBuffer(currentMediaIndex + 1);
463 return;
464 }.bind(this));
465 }; 401 };
466 402
467 /** 403 /**
...@@ -540,6 +476,11 @@ videojs.HlsHandler.prototype.setCurrentTime = function(currentTime) { ...@@ -540,6 +476,11 @@ videojs.HlsHandler.prototype.setCurrentTime = function(currentTime) {
540 return currentTime; 476 return currentTime;
541 } 477 }
542 478
479 // if we are in the middle of appending a segment, let it finish up
480 if (this.pendingSegment_ && this.pendingSegment_.buffered) {
481 return currentTime;
482 }
483
543 this.lastSegmentLoaded_ = null; 484 this.lastSegmentLoaded_ = null;
544 485
545 // cancel outstanding requests and buffer appends 486 // cancel outstanding requests and buffer appends
...@@ -640,6 +581,7 @@ videojs.HlsHandler.prototype.cancelSegmentXhr = function() { ...@@ -640,6 +581,7 @@ videojs.HlsHandler.prototype.cancelSegmentXhr = function() {
640 this.segmentXhr_.abort(); 581 this.segmentXhr_.abort();
641 this.segmentXhr_ = null; 582 this.segmentXhr_ = null;
642 } 583 }
584
643 // clear out the segment being processed 585 // clear out the segment being processed
644 this.pendingSegment_ = null; 586 this.pendingSegment_ = null;
645 }; 587 };
...@@ -828,8 +770,8 @@ videojs.HlsHandler.prototype.findCurrentBuffered_ = function() { ...@@ -828,8 +770,8 @@ videojs.HlsHandler.prototype.findCurrentBuffered_ = function() {
828 if (buffered && buffered.length) { 770 if (buffered && buffered.length) {
829 // Search for a range containing the play-head 771 // Search for a range containing the play-head
830 for (i = 0; i < buffered.length; i++) { 772 for (i = 0; i < buffered.length; i++) {
831 if (buffered.start(i) <= currentTime && 773 if (buffered.start(i) - TIME_FUDGE_FACTOR <= currentTime &&
832 buffered.end(i) >= currentTime) { 774 buffered.end(i) + TIME_FUDGE_FACTOR >= currentTime) {
833 ranges = videojs.createTimeRanges(buffered.start(i), buffered.end(i)); 775 ranges = videojs.createTimeRanges(buffered.start(i), buffered.end(i));
834 ranges.indexOf = i; 776 ranges.indexOf = i;
835 return ranges; 777 return ranges;
...@@ -1143,6 +1085,74 @@ videojs.HlsHandler.prototype.drainBuffer = function(event) { ...@@ -1143,6 +1085,74 @@ videojs.HlsHandler.prototype.drainBuffer = function(event) {
1143 this.sourceBuffer.appendBuffer(bytes); 1085 this.sourceBuffer.appendBuffer(bytes);
1144 }; 1086 };
1145 1087
1088 videojs.HlsHandler.prototype.updateEndHandler_ = function () {
1089 var
1090 segmentInfo = this.pendingSegment_,
1091 segment,
1092 segments,
1093 playlist,
1094 currentMediaIndex,
1095 currentBuffered,
1096 timelineUpdates;
1097
1098 this.pendingSegment_ = null;
1099
1100 // stop here if the update errored or was aborted
1101 if (!segmentInfo) {
1102 return;
1103 }
1104
1105 playlist = this.playlists.media();
1106 segments = playlist.segments;
1107 currentMediaIndex = segmentInfo.mediaIndex + (segmentInfo.mediaSequence - playlist.mediaSequence);
1108 currentBuffered = this.findCurrentBuffered_();
1109
1110 // if we switched renditions don't try to add segment timeline
1111 // information to the playlist
1112 if (segmentInfo.playlist.uri !== this.playlists.media().uri) {
1113 return this.fillBuffer();
1114 }
1115
1116 // annotate the segment with any start and end time information
1117 // added by the media processing
1118 segment = playlist.segments[currentMediaIndex];
1119
1120 timelineUpdates = videojs.Hls.bufferedAdditions_(segmentInfo.buffered,
1121 this.tech_.buffered());
1122
1123 timelineUpdates.forEach(function (update) {
1124 if (segment) {
1125 if (update.end !== undefined) {
1126 segment.end = update.end;
1127 }
1128 }
1129 });
1130
1131 // if we've buffered to the end of the video, let the MediaSource know
1132 if (this.playlists.media().endList &&
1133 currentBuffered.length &&
1134 segments[segments.length - 1].end <= currentBuffered.end(0) &&
1135 this.mediaSource.readyState === 'open') {
1136 this.mediaSource.endOfStream();
1137 return;
1138 }
1139
1140 if (timelineUpdates.length ||
1141 segmentInfo.buffered.length !== this.tech_.buffered().length) {
1142 this.updateDuration(playlist);
1143 // check if it's time to download the next segment
1144 this.fillBuffer();
1145 return;
1146 }
1147
1148 // the last segment append must have been entirely in the
1149 // already buffered time ranges. just buffer forward until we
1150 // find a segment that adds to the buffered time ranges and
1151 // improves subsequent media index calculations.
1152 this.fillBuffer(currentMediaIndex + 1);
1153 return;
1154 };
1155
1146 /** 1156 /**
1147 * Attempt to retrieve the key for a particular media segment. 1157 * Attempt to retrieve the key for a particular media segment.
1148 */ 1158 */
......
...@@ -381,8 +381,8 @@ ...@@ -381,8 +381,8 @@
381 }); 381 });
382 equal(seekable.start(0), 0, 'starts at the earliest available segment'); 382 equal(seekable.start(0), 0, 'starts at the earliest available segment');
383 equal(seekable.end(0), 383 equal(seekable.end(0),
384 9 - (2 * 3), 384 9 - (2 + 2 + 1),
385 'allows seeking no further than three target durations from the end'); 385 'allows seeking no further than three segments from the end');
386 }); 386 });
387 387
388 })(window, window.videojs); 388 })(window, window.videojs);
......