Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
74 lines
2.8 KiB
JavaScript
Executable file
74 lines
2.8 KiB
JavaScript
Executable file
/* global performance */
|
|
(function(exports) {
|
|
'use strict';
|
|
|
|
function Seeker(player) {
|
|
this.player = player; // The <video> element we seek for
|
|
this.seekStartedAt = null; // When was the last call to fastSeek
|
|
this.currentSeekTime = null; // What time are we currently seeking to
|
|
this.nextSeekTime = null; // Where to seek when done with this one
|
|
this.player.addEventListener('seeked', this); // Find out when seeks end
|
|
}
|
|
|
|
// We may defer seek requests that are made less than this amount of
|
|
// time (in milliseconds) from the currently pending seek request
|
|
Seeker.SEEK_INTERVAL = 200; // milliseconds
|
|
|
|
// We may defer seek requests if the seek target is less than this
|
|
// distance (in seconds) away from the currently pending seek request
|
|
Seeker.SEEK_DISTANCE = 10; // seconds
|
|
|
|
/*
|
|
* Call this method to efficiently seek the video player to the
|
|
* specified time.
|
|
*
|
|
* When the user is dragging the time slider we may request a seek
|
|
* every 50ms or less. fastSeek() can take 100ms or more to
|
|
* complete. And it only seeks to the nearest keyframe so is
|
|
* probably only accurate to +/- 10 seconds, depending on the video.
|
|
* We want to avoid sending lots of redundant seek requests to gecko
|
|
* since this seems to cause performance problems. But at the same
|
|
* time, we don't want to have to wait for gecko to complete a seek
|
|
* to one position if the user now wants to seek to some position
|
|
* far away.
|
|
*
|
|
* So, if we're already seeking, and if the last seek request was
|
|
* not very long ago and if the target of that seek request was
|
|
* close to the target of this seek, then we defer this seek request
|
|
* until the current seek request finishes with a 'seeked' event.
|
|
* Because it is common to seek to 0, we'll never defer that request.
|
|
*/
|
|
Seeker.prototype.seekTo = function(time) {
|
|
if (this.currentSeekTime === time) { // If we are already seeking to time
|
|
return; // then we don't have to do anything.
|
|
}
|
|
|
|
var now = performance.now();
|
|
if (this.currentSeekTime === null ||
|
|
time === 0 ||
|
|
Math.abs(this.currentSeekTime - time) > Seeker.SEEK_DISTANCE ||
|
|
now - this.seekStartedAt > Seeker.SEEK_INTERVAL)
|
|
{
|
|
// In this case we want to actually request a new seek
|
|
this.player.fastSeek(time);
|
|
this.seekStartedAt = now;
|
|
this.currentSeekTime = time;
|
|
this.nextSeekTime = null;
|
|
}
|
|
else {
|
|
// In this case we defer the seek until the current seek ends
|
|
this.nextSeekTime = time;
|
|
}
|
|
};
|
|
|
|
// This is invoked when we get a seeked event from the player
|
|
Seeker.prototype.handleEvent = function() {
|
|
this.currentSeekTime = null;
|
|
this.seekStartedAt = null;
|
|
if (this.nextSeekTime !== null) {
|
|
this.seekTo(this.nextSeekTime);
|
|
}
|
|
};
|
|
|
|
exports.Seeker = Seeker;
|
|
}(window));
|