support multipart video

This commit is contained in:
rlx 2011-08-19 10:45:36 +00:00
parent 676cb72101
commit c5bde89971
2 changed files with 187 additions and 170 deletions

View file

@ -3,182 +3,196 @@
Ox.VideoElement = function(options, self) { Ox.VideoElement = function(options, self) {
self = self || {}; self = self || {};
var that = Ox.Element('<video>', self) var that = Ox.Element({}, self)
.defaults({ .defaults({
fps: 25, autoplay: false,
height: 0, preload: 'none',
loop: false, src: []
muted: false,
paused: false,
playInToOut: false,
points: [0, 0],
position: 0,
poster: '',
url: '',
width: 0
})
.options(options || {})
.attr({
//height: self.options.height,
poster: self.options.poster,
preload: 'auto',
src: self.options.url,
//width: self.options.width
})
.css({
height: self.options.height + 'px',
width: self.options.width + 'px'
}) })
.options(options || {});
self.options.src = Ox.isArray(self.options.src) ? self.options.src : [self.options.src];
Ox.print('VIDEO ELEMENT OPTIONS', self.options)
self.currentPart = 0;
self.duration = 0;
self.durations = self.options.src.map(function() {
return 0;
});
self.offsets = [];
self.parts = self.options.src.length;
self.paused = true;
self.$videos = self.options.src.map(function(src, i) {
return $('<video>')
.attr(Ox.extend({
preload: 'metadata',
src: src
}, i == 0 && self.options.autoplay ? {
autoplay: 'autoplay'
} : {}))
.css({position: 'absolute'})
.bind({ .bind({
ended: ended, ended: function() {
canplay: function() { if (i < self.parts - 1) {
Ox.print('canplay') setCurrentPart(self.currentPart + 1);
}, self.video.play();
durationchange: function() { } else {
Ox.print('durationchange') that.triggerEvent('ended');
}
}, },
loadedmetadata: function() { loadedmetadata: function() {
Ox.print('loadedmetadata', self.video.duration) self.durations[i] = self.videos[i].duration;
self.video.currentTime = self.options.position; Ox.print(i, 'lm', self.durations);
that.triggerEvent('loadedmetadata', { if (Ox.every(self.durations)) {
video: self.video self.duration = Ox.sum(self.durations);
}); self.offsets = Ox.range(self.parts).map(function(i) {
}, return Ox.sum(Ox.sub(self.durations, 0, i));
progress: function() {
that.triggerEvent('progress', {
video: self.video
}); });
Ox.print('s.o', self.offsets)
that.triggerEvent('loadedmetadata');
}
}, },
seeked: function() { seeked: function() {
that.triggerEvent('seeked'); that.triggerEvent('seeked');
}, },
seeking: function() { seeking: function() {
that.triggerEvent('seeking'); that.triggerEvent('seeking');
},
progress: function() {
} }
})
.hide()
.appendTo(that.$element);
}); });
self.videos = self.$videos.map(function($video) {
return $video[0];
});
self.$video = self.$videos[0].show();
self.video = self.$video[0];
$.extend(self, { function getCurrentTime() {
millisecondsPerFrame: 1000 / self.options.fps, return self.offsets[self.currentPart] + self.video.currentTime;
video: that.$element[0]
});
function ended() {
that.pause()
.triggerEvent('paused', {
position: self.options.position
});
} }
function playing() { function getset(key, value) {
var event = 'playing'; var ret;
self.options.position = Math.round(self.video.currentTime * self.options.fps) / self.options.fps; if (Ox.isUndefined(value)) {
if (self.options.playInToOut && self.options.position >= self.options.points[1]) { ret = self.video[key]
event = 'paused'; } else {
that.position(self.options.points[1]).pause(); self.video[key] = value;
ret = that;
} }
that.triggerEvent(event, { return ret;
position: self.options.position
});
} }
self.setOption = function(key, value) { function setCurrentPart(part) {
if (key == 'height') { Ox.print('sCP', part)
that.size(self.options.width, value); var css = {};
} else if (key == 'muted') { ['left', 'top', 'width', 'height'].forEach(function(key) {
that[value ? 'mute' : 'unmute'](); css[key] = self.$video.css(key);
} else if (key == 'paused') { });
that[value ? 'pause' : 'play'](); self.$video.hide();
} else if (key == 'points') { self.video.pause();
that.points(value); self.$video = self.$videos[part].css(css).show();
} else if (key == 'width') { self.video = self.$video[0];
that.size(value, self.options.height); !self.paused && self.video.play();
self.currentPart = part;
Ox.print('sCP', part, self.video.src)
} }
function setCurrentTime(time) {
var currentPart, currentTime;
Ox.loop(self.parts - 1, -1, -1, function(i) {
if (self.offsets[i] <= time) {
currentPart = i;
currentTime = time - self.offsets[i];
return false;
}
});
Ox.print('sCT', time, currentPart, currentTime);
if (currentPart != self.currentPart) {
setCurrentPart(currentPart);
}
self.video.currentTime = currentTime;
}
that.animate = function() {
self.$video.animate.apply(self.$video, arguments);
return that;
}
that.buffered = function() {
return self.video.buffered;
}; };
that.mute = function() { that.currentTime = function() {
self.options.muted = true; var ret;
self.video.muted = true; if (arguments.length == 0) {
ret = getCurrentTime();
} else {
setCurrentTime(arguments[0]);
ret = that;
}
return ret;
};
that.css = function() {
self.$video.css.apply(self.$video, arguments);
return that; return that;
}; };
that.duration = function() {
return self.duration;
};
that.muted = function() { that.muted = function() {
return self.options.muted; return getset('muted', arguments[0]);
} };
that.pause = function() { that.pause = function() {
self.options.paused = true; self.paused = true;
self.options.playInToOut = false;
self.video.pause(); self.video.pause();
clearInterval(self.playInterval);
return that; return that;
}; };
that.paused = function() {
return self.options.paused;
}
that.play = function() { that.play = function() {
self.options.paused = false; self.paused = false;
self.video.play(); self.video.play();
self.playInterval = setInterval(playing, self.millisecondsPerFrame);
return that; return that;
}; };
that.playInToOut = function() { that.src = function() {
self.options.playInToOut = true; var ret;
that.position(self.options.points[0]);
self.options.paused && that.play();
return that;
};
that.points = function(points) {
self.options.points = points;
}
that.position = function(pos) {
// fixme: why not use options??
if (arguments.length == 0) { if (arguments.length == 0) {
return self.video.currentTime; ret = self.video.src;
} else { } else {
self.options.position = pos; self.options.src = Ox.isArray(arguments[0]) ? arguments[0] : [arguments[0]];
self.video.currentTime = self.options.position; self.videos[currentPart].src = self.options.src[currentPart];
return that; self.videos.forEach(function(video, i) {
if (i != currentPart) {
video.src = self.options.src[i];
} }
})
ret = that;
}
return ret;
}; };
that.size = function(width, height) { that.videoHeight = function() {
// fixme: why options? use css! return self.video.videoHeight;
if (arguments.length == 0) {
return {
width: self.options.width,
height: self.options.height
};
} else {
self.options.width = width;
self.options.height = height;
that.css({
width: width + 'px',
height: height + 'px'
});
return that;
}
}; };
that.toggleMute = function() { that.videoWidth = function() {
self.video.muted = !self.video.muted; return self.video.videoWidth;
return that; };
that.volume = function(value) {
return getset('volume', arguments[0]);
} }
that.togglePlay = function() {
self.options.paused = !self.options.paused;
that[self.options.paused ? 'pause' : 'play']();
}
that.unmute = function() {
self.video.muted = false;
return that;
};
return that; return that;
}; };

View file

@ -24,6 +24,7 @@ Ox.VideoPlayer <f> Generic Video Player
externalControls <b|false> If true, controls are outside the video externalControls <b|false> If true, controls are outside the video
find <s|''> Query string find <s|''> Query string
focus <s|'click'> focus on 'click', 'load' or 'mouseover' focus <s|'click'> focus on 'click', 'load' or 'mouseover'
format <s|''> video format (like 'webm')
fps <n|25> Frames per second fps <n|25> Frames per second
fullscreen <b|false> If true, video is in fullscreen fullscreen <b|false> If true, video is in fullscreen
height <n|144> Height in px (excluding external controls) height <n|144> Height in px (excluding external controls)
@ -82,6 +83,7 @@ Ox.VideoPlayer = function(options, self) {
externalControls: false, externalControls: false,
find: '', find: '',
focus: 'click', focus: 'click',
format: '',
fps: 25, fps: 25,
fullscreen: false, fullscreen: false,
height: 144, height: 144,
@ -131,11 +133,14 @@ Ox.VideoPlayer = function(options, self) {
if (Ox.isString(self.options.video)) { if (Ox.isString(self.options.video)) {
self.video = self.options.video; self.video = self.options.video;
} else { } else {
/*
self.resolutions = Ox.sort(Object.keys(self.options.video)); self.resolutions = Ox.sort(Object.keys(self.options.video));
if (!(self.options.resolution in self.options.video)) { if (!(self.options.resolution in self.options.video)) {
self.options.resolution = self.resolutions[0]; self.options.resolution = self.resolutions[0];
} }
self.video = self.options.video[self.options.resolution]; self.video = self.options.video[self.options.resolution];
*/
self.video = self.options.video(self.options.resolution, self.options.format)
} }
if (self.options.playInToOut) { if (self.options.playInToOut) {
@ -266,19 +271,17 @@ Ox.VideoPlayer = function(options, self) {
} }
}); });
self.$video = $('<video>') self.$video = Ox.VideoElement(
.attr(Ox.extend({ Ox.extend({
preload: self.options.preload, preload: self.options.preload,
src: self.video src: self.video
}, !self.options.paused ? { }, !self.options.paused ? {
autoplay: 'autoplay' autoplay: 'autoplay'
} : {}/*, self.options.poster ? { } : {}/*, self.options.poster ? {
poster: self.options.poster poster: self.options.poster
} : {}*/)) } : {}*/)
.css({ )
position: 'absolute' .bindEvent(Ox.extend({
})
.bind(Ox.extend({
ended: ended, ended: ended,
loadedmetadata: loadedmetadata, loadedmetadata: loadedmetadata,
seeked: seeked, seeked: seeked,
@ -288,7 +291,7 @@ Ox.VideoPlayer = function(options, self) {
} : {})) } : {}))
.appendTo(self.$videoContainer); .appendTo(self.$videoContainer);
self.video = self.$video[0]; self.$video.$element.css({position: 'absolute'});
} else { } else {
@ -1119,8 +1122,8 @@ Ox.VideoPlayer = function(options, self) {
if ($.browser.mozilla) { if ($.browser.mozilla) {
//Ox.print(e, e.layerX - 56) //Ox.print(e, e.layerX - 56)
return Ox.limit( return Ox.limit(
(e.layerX - 48 - self.barHeight / 2) / self.timelineImageWidth * self.video.duration, (e.layerX - 48 - self.barHeight / 2) / self.timelineImageWidth * self.$video.duration(),
0, self.video.duration 0, self.$video.duration()
); );
} else { } else {
/*Ox.print(e.offsetX, Ox.limit( /*Ox.print(e.offsetX, Ox.limit(
@ -1128,8 +1131,8 @@ Ox.VideoPlayer = function(options, self) {
0, self.video.duration 0, self.video.duration
))*/ ))*/
return Ox.limit( return Ox.limit(
(e.offsetX - self.barHeight / 2) / self.timelineImageWidth * self.video.duration, (e.offsetX - self.barHeight / 2) / self.timelineImageWidth * self.$video.duration(),
0, self.video.duration 0, self.$video.duration()
); );
} }
} }
@ -1177,8 +1180,8 @@ Ox.VideoPlayer = function(options, self) {
imageData = context.getImageData(0, 0, width, height), imageData = context.getImageData(0, 0, width, height),
data = imageData.data; data = imageData.data;
self.buffered.forEach(function(range) { self.buffered.forEach(function(range) {
var left = Math.round(range[0] * width / self.video.duration), var left = Math.round(range[0] * width / self.$video.duration()),
right = Math.round(range[1] * width / self.video.duration); right = Math.round(range[1] * width / self.$video.duration());
Ox.loop(left, right, function(x) { Ox.loop(left, right, function(x) {
Ox.loop(height, function(y) { Ox.loop(height, function(y) {
index = x * 4 + y * 4 * width; index = x * 4 + y * 4 * width;
@ -1331,7 +1334,7 @@ Ox.VideoPlayer = function(options, self) {
} }
function hideControls() { function hideControls() {
Ox.print('hideControls'); //Ox.print('hideControls');
clearTimeout(self.interfaceTimeout); clearTimeout(self.interfaceTimeout);
self.interfaceTimeout = setTimeout(function() { self.interfaceTimeout = setTimeout(function() {
if (!self.exitFullscreen && !self.inputHasFocus && !self.mouseIsInControls) { if (!self.exitFullscreen && !self.inputHasFocus && !self.mouseIsInControls) {
@ -1403,8 +1406,8 @@ Ox.VideoPlayer = function(options, self) {
self.loadedMetadata = true; self.loadedMetadata = true;
self.videoWidth = self.video.videoWidth; self.videoWidth = self.$video.videoWidth();
self.videoHeight = self.video.videoHeight; self.videoHeight = self.$video.videoHeight();
self.videoCSS = getVideoCSS(); self.videoCSS = getVideoCSS();
self.posterMarkerCSS = getPosterMarkerCSS(); self.posterMarkerCSS = getPosterMarkerCSS();
self.$video.css(self.videoCSS); self.$video.css(self.videoCSS);
@ -1414,10 +1417,10 @@ Ox.VideoPlayer = function(options, self) {
}); });
self.out = self.options.playInToOut && self.out = self.options.playInToOut &&
self.options.out < self.video.duration ? self.options.out < self.$video.duration() ?
self.options.out : self.video.duration; self.options.out : self.$video.duration();
self.options.duration = self.out - self['in']; self.options.duration = self.out - self['in'];
self.video.currentTime = self.options.position; self.$video.currentTime(self.options.position);
self.options.paused && self.options.showMarkers && setMarkers(); self.options.paused && self.options.showMarkers && setMarkers();
self.options.paused && self.playOnLoad && togglePaused('button'); self.options.paused && self.playOnLoad && togglePaused('button');
@ -1469,7 +1472,7 @@ Ox.VideoPlayer = function(options, self) {
} }
function playing() { function playing() {
self.options.position = self.video.currentTime; self.options.position = self.$video.currentTime();
if ( if (
(self.options.playInToOut || self.playInToOut) && (self.options.playInToOut || self.playInToOut) &&
self.options.position >= self.options.out self.options.position >= self.options.out
@ -1496,7 +1499,7 @@ Ox.VideoPlayer = function(options, self) {
} }
function progress() { function progress() {
var buffered = self.video.buffered; var buffered = self.$video.buffered();
for (var i = 0; i < buffered.length; i++) { for (var i = 0; i < buffered.length; i++) {
self.buffered[i] = [buffered.start(i), buffered.end(i)]; self.buffered[i] = [buffered.start(i), buffered.end(i)];
// fixme: firefox weirdness // fixme: firefox weirdness
@ -1562,7 +1565,7 @@ Ox.VideoPlayer = function(options, self) {
self.$position && self.$position.html(formatPosition()); self.$position && self.$position.html(formatPosition());
if (self.options.type == 'play') { if (self.options.type == 'play') {
if (self.loadedMetadata && from != 'video') { if (self.loadedMetadata && from != 'video') {
self.video.currentTime = self.options.position; self.$video.currentTime(self.options.position);
} }
if (self.iconIsVisible) { if (self.iconIsVisible) {
self.$playIcon.animate({ self.$playIcon.animate({
@ -1592,7 +1595,7 @@ Ox.VideoPlayer = function(options, self) {
} }
self.loadedMetadata = false; self.loadedMetadata = false;
showLoadingIcon(); showLoadingIcon();
self.video.src = self.options.video[self.options.resolution]; self.$video.src(self.options.video[self.options.resolution]);
self.$playButton && self.$playButton.options({ self.$playButton && self.$playButton.options({
disabled: true disabled: true
}); });
@ -1691,10 +1694,10 @@ Ox.VideoPlayer = function(options, self) {
self.options.volume = volume; self.options.volume = volume;
if (!!self.options.volume == self.options.muted) { if (!!self.options.volume == self.options.muted) {
self.options.muted = !self.options.muted; self.options.muted = !self.options.muted;
self.video.muted = self.options.muted; self.$video.muted(self.options.muted);
self.$muteButton.toggleTitle(); self.$muteButton.toggleTitle();
} }
self.video.volume = self.options.volume; self.$video.volume(self.options.volume);
self.$volumeButton.attr({ self.$volumeButton.attr({
src: getVolumeImageURL() src: getVolumeImageURL()
}); });
@ -1705,7 +1708,7 @@ Ox.VideoPlayer = function(options, self) {
} }
function showControls() { function showControls() {
Ox.print('showControls'); //Ox.print('showControls');
clearTimeout(self.interfaceTimeout); clearTimeout(self.interfaceTimeout);
if (!self.interfaceIsVisible) { if (!self.interfaceIsVisible) {
self.interfaceIsVisible = true; self.interfaceIsVisible = true;
@ -1818,7 +1821,7 @@ Ox.VideoPlayer = function(options, self) {
setPosition(parsePositionInput(self.$positionInput.options('value'))); setPosition(parsePositionInput(self.$positionInput.options('value')));
if (self.playOnSubmit) { if (self.playOnSubmit) {
togglePaused(); togglePaused();
self.video.play(); self.$video.play();
self.playOnSubmit = false; self.playOnSubmit = false;
} }
if (self.focus == 'mouseenter' && !self.mouseHasLeft) { if (self.focus == 'mouseenter' && !self.mouseHasLeft) {
@ -1842,7 +1845,7 @@ Ox.VideoPlayer = function(options, self) {
self.options.fullscreen = !self.options.fullscreen; self.options.fullscreen = !self.options.fullscreen;
if (!self.options.paused) { if (!self.options.paused) {
// video won't keep playing accross detach/append // video won't keep playing accross detach/append
self.video.pause(); self.$video.pause();
playOnFullscreen = true; playOnFullscreen = true;
} }
if (self.options.fullscreen) { if (self.options.fullscreen) {
@ -1861,7 +1864,7 @@ Ox.VideoPlayer = function(options, self) {
}) })
.appendTo(Ox.UI.$body); .appendTo(Ox.UI.$body);
setSizes(function() { setSizes(function() {
playOnFullscreen && self.video.play(); playOnFullscreen && self.$video.play();
that.bind({ that.bind({
mousemove: function() { mousemove: function() {
showControls(); showControls();
@ -1898,7 +1901,7 @@ Ox.VideoPlayer = function(options, self) {
zIndex: 1 zIndex: 1
}) })
.appendTo(self.$parent); .appendTo(self.$parent);
playOnFullscreen && self.video.play(); playOnFullscreen && self.$video.play();
self.options.enableKeyboard && that.gainFocus(); self.options.enableKeyboard && that.gainFocus();
//showControls(); //showControls();
}); });
@ -1911,10 +1914,10 @@ Ox.VideoPlayer = function(options, self) {
function toggleMuted(from) { function toggleMuted(from) {
showVolume(); showVolume();
self.options.muted = !self.options.muted; self.options.muted = !self.options.muted;
self.video.muted = self.options.muted; self.$video.muted(self.options.muted);
if (!self.options.muted && !self.options.volume) { if (!self.options.muted && !self.options.volume) {
self.options.volume = 1; self.options.volume = 1;
self.video.volume = 1; self.$video.volume(1);
} }
if (self.$muteButton && from != 'button') { if (self.$muteButton && from != 'button') {
self.$muteButton.toggleTitle(); self.$muteButton.toggleTitle();
@ -1939,7 +1942,7 @@ Ox.VideoPlayer = function(options, self) {
paused: self.options.paused paused: self.options.paused
}); });
if (self.options.paused) { if (self.options.paused) {
self.video.pause(); self.$video.pause();
clearInterval(self.playInterval); clearInterval(self.playInterval);
if (self.options.showIcon) { if (self.options.showIcon) {
togglePlayIcon(); togglePlayIcon();
@ -1951,7 +1954,7 @@ Ox.VideoPlayer = function(options, self) {
if (self.options.playInToOut && self.options.position > self.options.out - self.secondsPerFrame) { if (self.options.playInToOut && self.options.position > self.options.out - self.secondsPerFrame) {
setPosition(self.options['in']); setPosition(self.options['in']);
} }
self.video.play(); self.$video.play();
self.playInterval = setInterval(playing, self.millisecondsPerFrame); self.playInterval = setInterval(playing, self.millisecondsPerFrame);
if (self.options.showIcon) { if (self.options.showIcon) {
self.options.showIcon && self.$playIcon.animate({ self.options.showIcon && self.$playIcon.animate({