oxjs/source/Ox.UI/js/Video/Ox.VideoElement.js

462 lines
14 KiB
JavaScript
Raw Normal View History

2011-07-29 18:48:43 +00:00
// vim: et:ts=4:sw=4:sts=4:ft=javascript
2011-11-05 16:46:53 +00:00
'use strict';
2011-09-14 14:34:33 +00:00
/*@
Ox.VideoElement <f:Ox.Element> VideoElement Object
() -> <f> VideoElement Object
(options) -> <f> VideoElement Object
(options, self) -> <f> VideoElement Object
options <o> Options object
self <o> shared private variable
@*/
2011-04-22 22:03:10 +00:00
Ox.VideoElement = function(options, self) {
self = self || {};
2011-08-19 10:45:36 +00:00
var that = Ox.Element({}, self)
2011-04-22 22:03:10 +00:00
.defaults({
2011-08-19 10:45:36 +00:00
autoplay: false,
preload: 'none',
src: []
2011-04-22 22:03:10 +00:00
})
2011-10-22 21:03:42 +00:00
.options(options || {})
.css({width: '100%', height: '100%'});
2011-08-19 10:45:36 +00:00
Ox.Log('Video', 'VIDEO ELEMENT OPTIONS', self.options);
2011-08-19 10:45:36 +00:00
2011-08-20 09:48:28 +00:00
self.items = [];
2011-08-19 10:45:36 +00:00
self.paused = true;
2011-08-20 09:48:28 +00:00
self.$video = $('<div>');
2011-08-19 10:45:36 +00:00
2011-08-20 09:48:28 +00:00
if (Ox.isFunction(self.options.src)) {
self.isPlaylist = true;
self.currentItem = 0;
self.currentPage = 0;
self.loadedMetadata = false;
self.pageLength = 2;
self.options.src(function(items) {
self.numberOfItems = items;
self.numberOfPages = Math.ceil(self.numberOfItems / self.pageLength);
loadPages(function() {
2011-11-04 15:54:28 +00:00
Ox.Log('Video', 'VIDEO PAGES LOADED');
2011-08-20 09:48:28 +00:00
setCurrentItem(0);
if (!self.loadedMedatata) {
self.loadedMetadata = true;
that.triggerEvent('loadedmetadata');
that.triggerEvent('pointschange'); // fixme: needs to be triggered again, loadedmetadata messes with duration
2011-04-22 22:03:10 +00:00
}
2011-08-20 09:48:28 +00:00
});
});
} else {
self.numberOfItems = 1;
self.items.push(loadItem(self.options.src));
}
function getCurrentPage() {
return Math.floor(self.currentItem / self.pageLength);
}
2011-04-22 22:03:10 +00:00
2011-08-19 10:45:36 +00:00
function getCurrentTime() {
2011-08-20 09:48:28 +00:00
return self.items[self.currentItem].offsets[self.currentPart] + self.video.currentTime;
2011-04-22 22:03:10 +00:00
}
2011-08-19 10:45:36 +00:00
function getset(key, value) {
var ret;
if (Ox.isUndefined(value)) {
ret = self.video[key];
2011-08-19 10:45:36 +00:00
} else {
self.video[key] = value;
ret = that;
2011-04-22 22:03:10 +00:00
}
2011-08-19 10:45:36 +00:00
return ret;
}
2011-08-20 09:48:28 +00:00
function loadPage(page, callback) {
Ox.Log('Video', 'VIDEO loadPage', page);
2011-08-20 09:48:28 +00:00
//page = Ox.mod(page, self.numberOfPages);
var loadedmetadata = 0,
start = page * self.pageLength,
stop = Math.min(start + self.pageLength, self.numberOfItems),
pageLength = stop - start;
if (!self.items[start]) {
self.options.src([start, stop], function(data) {
data.forEach(function(data, i) {
self.items[start + i] = loadItem(data.parts, data.points, function(item) {
if (++loadedmetadata == pageLength) {
Ox.Log('Video', 'VIDEO page', page, 'loaded');
2011-08-20 09:48:28 +00:00
callback && callback();
}
});
});
});
} else {
Ox.Log('Video', 'PAGE IN CACHE');
2011-08-20 09:48:28 +00:00
callback && callback();
}
}
function loadPages(callback) {
var currentPage = self.currentPage,
nextPage = Ox.mod(currentPage + 1, self.numberOfPages),
2011-10-24 13:13:00 +00:00
previousPage = Ox.mod(currentPage - 1, self.numberOfPages);
2011-08-20 09:48:28 +00:00
loadPage(currentPage, function() {
if (nextPage != currentPage) {
loadPage(nextPage, function() {
if (previousPage != currentPage && previousPage != nextPage) {
unloadPage(previousPage);
}
});
}
callback && callback();
});
}
function loadItem(src, points, callback) {
src = Ox.isArray(src) ? src : [src];
var item = {
currentPart: 0,
duration: 0,
durations: src.map(function() {
return 0;
}),
offsets: [],
parts: src.length
};
if (points) {
item.points = points;
}
item.$videos = src.map(function(src, i) {
// in all browsers except firefox,
// loadedmetadata fires only once per src
src += '?' + Ox.uid();
return $('<video>')
.css({position: 'absolute'})
.bind({
ended: function() {
2011-08-20 23:11:38 +00:00
if (i < item.parts - 1) {
2011-08-20 09:48:28 +00:00
setCurrentPart(self.currentPart + 1);
self.video.play();
} /*else if (self.isPlaylist) {
setCurrentItem(self.currentItem + 1);
self.video.play();
}*/ else {
self.ended = true;
self.paused = true;
that.triggerEvent('ended');
}
},
loadedmetadata: function() {
item.durations[i] = item.videos[i].duration;
if (self.isPlaylist && i == 0) {
item.videos[0].currentTime = item.points[0];
}
if (Ox.every(item.durations)) {
item.duration = Ox.sum(item.durations);
item.offsets = Ox.range(item.parts).map(function(i) {
return Ox.sum(Ox.sub(item.durations, 0, i));
});
2011-11-04 15:54:28 +00:00
//Ox.Log('Video', 'METADATA OF', src, 'LOADED', item)
2011-08-20 09:48:28 +00:00
if (self.isPlaylist) {
callback && callback();
} else {
setCurrentItem(0);
that.triggerEvent('loadedmetadata');
}
}
},
progress: function() {
// not implemented
},
seeked: function() {
that.triggerEvent('seeked');
},
seeking: function() {
that.triggerEvent('seeking');
},
stop: function() {
// custom event to be triggered on removal from the DOM
self.video.pause();
self.video.src = '';
that.triggerEvent('ended');
}
})
.attr(Ox.extend({
preload: 'metadata',
src: src
}, i == 0 && self.options.autoplay ? {
autoplay: 'autoplay'
} : {}))
.hide()
.appendTo(that.$element);
});
item.videos = item.$videos.map(function($video) {
return $video[0];
});
2011-10-22 21:03:42 +00:00
self.$brightness = $('<div>').css({
width: '100%',
height: '100%',
background: 'rgb(0, 0, 0)',
opacity: 0
})
.appendTo(that.$element);
2011-08-20 09:48:28 +00:00
return item;
}
function setCurrentItem(item) {
2011-11-04 15:54:28 +00:00
Ox.Log('Video', 'scI', item);
2011-08-20 09:48:28 +00:00
var interval;
item = Ox.mod(item, self.numberOfItems);
self.video && self.video.pause();
if (self.items[item]) {
set();
} else {
that.triggerEvent('seeking');
interval = setInterval(function() {
2011-11-04 15:54:28 +00:00
Ox.Log('Video', 'ITEM', item, 'NOT AVAILABLE');
2011-08-20 09:48:28 +00:00
if (self.items[item]) {
clearInterval(interval);
that.triggerEvent('seeked');
set();
}
}, 250);
}
function set() {
self.currentItem = item;
self.currentPart = -1;
setCurrentTime(0);
if (self.isPlaylist) {
that.triggerEvent('pointschange');
that.triggerEvent('sizechange');
self.currentPage = getCurrentPage();
loadPages();
}
}
}
2011-08-19 10:45:36 +00:00
function setCurrentPart(part) {
2011-11-04 15:54:28 +00:00
Ox.Log('Video', 'sCP', part);
var css = {},
muted = false,
volume = 1;
2011-08-19 10:45:36 +00:00
['left', 'top', 'width', 'height'].forEach(function(key) {
css[key] = self.$video.css(key);
2011-04-22 22:03:10 +00:00
});
2011-08-20 09:48:28 +00:00
if (self.video) {
self.$video.hide();
self.video.pause();
self.video.currentTime = 0;
volume = self.video.volume;
muted = self.video.muted;
2011-08-20 09:48:28 +00:00
}
self.$video = self.items[self.currentItem].$videos[part].css(css).show();
2011-08-19 10:45:36 +00:00
self.video = self.$video[0];
self.video.volume = volume;
self.video.muted = muted;
2011-08-19 10:45:36 +00:00
!self.paused && self.video.play();
self.currentPart = part;
Ox.Log('Video', 'sCP', part, self.video.src);
2011-04-22 22:03:10 +00:00
}
2011-08-19 10:45:36 +00:00
function setCurrentTime(time) {
2011-11-04 15:54:28 +00:00
Ox.Log('Video', 'sCT', time);
2011-08-20 09:48:28 +00:00
var currentPart, currentTime,
item = self.items[self.currentItem];
Ox.loop(item.parts - 1, -1, -1, function(i) {
if (item.offsets[i] <= time) {
2011-08-19 10:45:36 +00:00
currentPart = i;
2011-08-20 09:48:28 +00:00
currentTime = time - item.offsets[i];
2011-08-19 10:45:36 +00:00
return false;
}
});
2011-11-04 15:54:28 +00:00
Ox.Log('Video', 'sCT', time, currentPart, currentTime);
2011-08-19 10:45:36 +00:00
if (currentPart != self.currentPart) {
setCurrentPart(currentPart);
2011-04-22 22:03:10 +00:00
}
2011-08-19 10:45:36 +00:00
self.video.currentTime = currentTime;
}
2011-08-20 09:48:28 +00:00
function unloadPage(page) {
//page = Ox.mod(page, self.numberOfPages);
Ox.Log('Video', 'unloadPage', page);
2011-08-20 09:48:28 +00:00
var start = page * self.pageLength,
stop = Math.min(start + self.pageLength, self.numberOfItems);
Ox.range(start, stop).forEach(function(i) {
if (self.items[i]) {
self.items[i].$videos.forEach(function($video) {
2011-10-24 13:13:00 +00:00
$video[0].src = '';
2011-08-20 09:48:28 +00:00
$video.remove();
});
delete self.items[i];
}
});
}
2011-09-14 14:34:33 +00:00
/*@
animate <f> animate
@*/
2011-08-19 10:45:36 +00:00
that.animate = function() {
self.$video.animate.apply(self.$video, arguments);
return that;
2011-09-14 14:34:33 +00:00
};
2011-08-19 10:45:36 +00:00
2011-10-22 21:03:42 +00:00
/*@
brightness <f> get/set brightness
@*/
that.brightness = function() {
var ret;
if (arguments.length == 0) {
ret = 1 - parseFloat(self.$brightness.css('opacity'));
} else {
self.$brightness.css({opacity: 1 - arguments[0]});
ret = that;
}
return ret;
};
2011-09-14 14:34:33 +00:00
/*@
buffered <f> buffered
@*/
2011-08-19 10:45:36 +00:00
that.buffered = function() {
return self.video.buffered;
2011-04-22 22:03:10 +00:00
};
2011-09-14 14:34:33 +00:00
/*@
currentTime <f> get/set currentTime
@*/
2011-08-19 10:45:36 +00:00
that.currentTime = function() {
var ret;
2011-08-19 14:44:03 +00:00
self.ended = false;
2011-08-19 10:45:36 +00:00
if (arguments.length == 0) {
ret = getCurrentTime();
} else {
setCurrentTime(arguments[0]);
ret = that;
}
return ret;
};
2011-09-14 14:34:33 +00:00
/*@
css <f> css
@*/
2011-08-19 10:45:36 +00:00
that.css = function() {
2011-08-20 09:48:28 +00:00
var interval;
if (self.$video) {
self.$video.css.apply(self.$video, arguments);
} else {
interval = setInterval(function() {
2011-11-04 15:54:28 +00:00
Ox.Log('Video', 'VIDEO NOT YET AVAILABLE');
2011-08-20 09:48:28 +00:00
if (self.$video) {
clearInterval(interval);
self.$video.css.apply(self.$video, arguments);
}
}, 250);
}
2011-04-22 22:03:10 +00:00
return that;
};
2011-09-14 14:34:33 +00:00
/*@
duration <f> duration
@*/
2011-08-19 10:45:36 +00:00
that.duration = function() {
2011-08-20 09:48:28 +00:00
// 86399
return self.items[self.currentItem].duration;
2011-08-19 10:45:36 +00:00
};
2011-09-14 14:34:33 +00:00
/*@
muted <f> get/set muted
@*/
2011-04-22 22:03:10 +00:00
that.muted = function() {
2011-08-19 10:45:36 +00:00
return getset('muted', arguments[0]);
};
2011-04-22 22:03:10 +00:00
2011-09-14 14:34:33 +00:00
/*@
points <f> get points
@*/
2011-08-20 09:48:28 +00:00
that.points = function() {
return self.items[self.currentItem].points;
};
2011-09-14 14:34:33 +00:00
/*@
pause <f> pause
@*/
2011-04-22 22:03:10 +00:00
that.pause = function() {
2011-08-19 10:45:36 +00:00
self.paused = true;
2011-04-22 22:03:10 +00:00
self.video.pause();
return that;
};
2011-09-14 14:34:33 +00:00
/*@
play <f> play
@*/
2011-04-22 22:03:10 +00:00
that.play = function() {
2011-08-19 14:44:03 +00:00
if (self.ended) {
that.currentTime(0);
self.ended = false;
}
2011-08-19 10:45:36 +00:00
self.paused = false;
2011-04-22 22:03:10 +00:00
self.video.play();
return that;
};
2011-09-14 14:34:33 +00:00
/*@
playNext <f> play next
@*/
2011-08-20 09:48:28 +00:00
that.playNext = function() {
Ox.Log('Video', 'PLAY NEXT');
2011-08-20 09:48:28 +00:00
setCurrentItem(self.currentItem + 1);
self.video.play();
};
2011-09-14 14:34:33 +00:00
/*@
playPrevious <f> play previous
@*/
2011-08-20 09:48:28 +00:00
that.playPrevious = function() {
setCurrentItem(self.currentItem - 1);
};
2011-09-14 14:34:33 +00:00
/*@
src <f> get/set src
@*/
2011-08-19 10:45:36 +00:00
that.src = function() {
var ret;
2011-04-22 22:03:10 +00:00
if (arguments.length == 0) {
2011-08-19 10:45:36 +00:00
ret = self.video.src;
2011-04-22 22:03:10 +00:00
} else {
2011-08-19 10:45:36 +00:00
self.options.src = Ox.isArray(arguments[0]) ? arguments[0] : [arguments[0]];
self.$video[self.currentPart].src = self.options.src[self.currentPart];
self.$video.each(function(video, i) {
if (i != self.currentPart) {
2011-08-19 10:45:36 +00:00
video.src = self.options.src[i];
}
});
2011-08-19 10:45:36 +00:00
ret = that;
2011-04-22 22:03:10 +00:00
}
2011-08-19 10:45:36 +00:00
return ret;
2011-04-22 22:03:10 +00:00
};
2011-09-14 14:34:33 +00:00
/*@
videoHeight <f> get videoHeight
@*/
2011-08-19 10:45:36 +00:00
that.videoHeight = function() {
return self.video.videoHeight;
2011-04-22 22:03:10 +00:00
};
2011-09-14 14:34:33 +00:00
/*@
videoWidth <f> get videoWidth
@*/
2011-08-19 10:45:36 +00:00
that.videoWidth = function() {
return self.video.videoWidth;
};
2011-04-22 22:03:10 +00:00
2011-09-14 14:34:33 +00:00
/*@
volume <f> get/set volume
@*/
2011-08-19 10:45:36 +00:00
that.volume = function(value) {
return getset('volume', arguments[0]);
};
2011-04-22 22:03:10 +00:00
return that;
};