diff johndyer-mediaelement-13fa20a/src/js/mep-feature-backlight.js @ 0:032bc65ebafc

added core components
author George Fazekas <gyorgy.fazekas@eecs.qmul.ac.uk>
date Wed, 06 Mar 2013 15:45:48 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/johndyer-mediaelement-13fa20a/src/js/mep-feature-backlight.js	Wed Mar 06 15:45:48 2013 +0000
@@ -0,0 +1,437 @@
+(function($) {
+
+	$.extend(mejs.MepDefaults, {
+		backlightBackground: [0,0,0],
+		backlightHorizontalLights: 5,
+		backlightVerticalLights: 5,
+		backlightSize: 50,
+		backlightTimeout: 200
+	});
+
+
+
+	MediaElementPlayer.prototype.buildbacklight = function(player, controls, layers, media) {
+		if (!player.isVideo)
+			return;
+
+		//http://www.splashnology.com/blog/html5/382.html
+
+		var 
+			mediaContainer = player.container.find('.mejs-mediaelement').parent(),
+			border = $('<div class="mejs-border"></div>')
+				.prependTo(mediaContainer)
+				.css('position','absolute')
+				.css('top','-10px')
+				.css('left','-10px')
+				.css('border','solid 10px #010101')
+				.width(player.width).height(player.height),
+			glowBase = $('<div class="mejs-backlight-glow"></div>')
+				.prependTo(mediaContainer)
+				.css('position','absolute')
+				.css('display','none')
+				.css('top',0)
+				.css('left',0)
+				.width(player.width).height(player.height),
+			base = $('<div class="mejs-backlight"></div>')
+				.prependTo(mediaContainer)
+				.css('position','absolute')
+				.css('top',0)
+				.css('left',0)
+				.width(player.width).height(player.height),
+
+			i,
+			copyCanvas = document.createElement('canvas'),
+			copyContext = copyCanvas.getContext('2d'),
+			pixels,
+			keepUpdating = true,
+			isActive = true,
+			timer = null,
+			glowCanvas = document.createElement('canvas'),
+			glowContext = glowCanvas.getContext('2d'),
+			size = player.options.backlightSize,
+			backgroundColor = player.options.backlightBackground,
+			gradient,
+			width = player.width,
+			height = player.height;
+
+		// set sizes
+		copyCanvas.width = width;
+		copyCanvas.height = height;
+		glowCanvas.width = width + size + size;
+		glowCanvas.height = height + size + size;
+
+		// draw glow overlay
+		// top
+		gradient = addGlow(backgroundColor,glowContext.createLinearGradient(size, size, size, 0));
+		glowContext.fillStyle = gradient; 
+		glowContext.fillRect(size, size, width, -size); 
+
+		// tr
+		gradient = addGlow(backgroundColor,glowContext.createRadialGradient(width+size, size, 0, width+size, size, size));
+		glowContext.fillStyle = gradient; 
+		glowContext.fillRect(width+size, size, size, -size); 
+
+		// right
+		gradient = addGlow(backgroundColor,glowContext.createLinearGradient(width+size, size, width+size+size, size));
+		glowContext.fillStyle = gradient; 
+		glowContext.fillRect(width+size, size, size, height); 
+
+		// br
+		gradient = addGlow(backgroundColor,glowContext.createRadialGradient(width+size, height+size, 0, width+size, height+size, size));
+		glowContext.fillStyle = gradient; 
+		glowContext.fillRect(width+size, height+size, size, size); 
+
+		// bottom
+		var gradient = addGlow(backgroundColor,glowContext.createLinearGradient(size, size+height, size, size+height+size));
+		glowContext.fillStyle = gradient; 
+		glowContext.fillRect(size, size+height, width, size); 
+
+		// bl
+		gradient = addGlow(backgroundColor,glowContext.createRadialGradient(size, height+size, 0, size, height+size, size));
+		glowContext.fillStyle = gradient; 
+		glowContext.fillRect(0, height+size, size, size); 
+
+		// left
+		gradient = addGlow(backgroundColor,glowContext.createLinearGradient(size, size, 0, size));
+		glowContext.fillStyle = gradient; 
+		glowContext.fillRect(size, size, -size, height); 
+
+		// tl
+		gradient = addGlow(backgroundColor,glowContext.createRadialGradient(size, size, 0, size, size, size));
+		glowContext.fillStyle = gradient; 
+		glowContext.fillRect(0, 0, size, size); 
+
+		$(glowCanvas)
+			.css('position','absolute')
+			.css('top',-size)
+			.css('left',-size)
+			.appendTo(glowBase);
+
+
+		// add toggle control
+		$('<div class="mejs-backlight-button mejs-backlight-active"><span></span></div>')
+			.appendTo(controls)
+			.click(function() {
+				if (isActive) {
+					delete timer;
+					timer = null;
+					base.hide();
+					glowBase.hide();
+					$(this)
+						.removeClass('mejs-backlight-active')
+						.addClass('mejs-backlight-inactive')
+				} else {
+					updateLights();
+					base.show();
+					glowBase.show();
+					$(this)
+						.removeClass('mejs-backlight-inactive')
+						.addClass('mejs-backlight-active')
+				}
+				isActive = !isActive;
+			});
+
+
+		// http://www.splashnology.com/blog/html5/382.html
+		function updateLights() {
+
+			// get a copy of video
+			copyContext.drawImage(media, 0, 0, media.width, media.height);
+
+			// create the gradient lights
+			addLights(base, copyCanvas, copyContext, 
+				player.options.backlightVerticalLights, 
+				player.options.backlightHorizontalLights, 
+				player.options.backlightSize, 
+				30);
+
+			if (keepUpdating && isActive) {
+				timer = setTimeout(updateLights, player.options.backlightTimeout);
+			}
+		}
+
+
+
+
+		//setTimeout(updateLights, timeOut);
+
+		media.addEventListener('play',function() {
+			if (isActive) {
+				keepUpdating = true;
+				updateLights();
+				glowBase.css('display','');
+			}
+		}, false);
+		media.addEventListener('pause',function() {
+			keepUpdating = false;
+		}, false);
+		media.addEventListener('ended',function() {
+			keepUpdating = false;
+		}, false);
+
+	};
+
+
+
+	function addLights(base, canvas, context, vBlocks, hBlocks, size, depth) {
+		base.empty();
+
+		var 
+			lightsCanvas = document.createElement('canvas'),
+			lightsContext = lightsCanvas.getContext('2d'),
+			width = canvas.width,
+			height = canvas.height,
+			g,
+			topLights = getMidColors(canvas, context, hBlocks, depth, 'top'),
+			bottomLights = getMidColors(canvas, context, hBlocks, depth, 'bottom'),
+			leftLights = getMidColors(canvas, context, vBlocks, depth, 'left'),
+			rightLights = getMidColors(canvas, context, vBlocks, depth, 'right'),
+			corners = [],
+			stopSize = 0;
+
+		lightsCanvas.width = width + size + size;
+		lightsCanvas.height = height + size + size;
+		lightsContext.globalCompositeOperation = 'xor'; //'darker'; //'lighter';
+
+		// draw four gradients
+		// create corners
+		corners.push(averageColor(topLights[topLights.length-1], rightLights[0]) );
+		corners.push(averageColor(bottomLights[bottomLights.length-1], rightLights[rightLights.length-1]) );
+		corners.push(averageColor(bottomLights[0], leftLights[leftLights.length-1]) );
+		corners.push(averageColor(topLights[0], leftLights[0]) );
+
+		// top
+		stopSize = 1 / topLights.length;
+		gradient = context.createLinearGradient(size, size, width+size, size);
+		gradient.addColorStop(0, 'rgb(' + adjustColor(corners[3]).join(',') + ')');
+		for (var i = 0, il = topLights.length; i < il; i++) {
+			gradient.addColorStop(i * stopSize + stopSize/2, 'rgb(' + adjustColor(topLights[i]).join(',') + ')');
+		}
+		gradient.addColorStop(1.0, 'rgb(' + adjustColor(corners[0]).join(',') + ')');
+		lightsContext.fillStyle = gradient;
+		lightsContext.fillRect(size, 0, width, size);
+
+		// right
+		gradient = context.createLinearGradient(size+width, size, size+width, size+height);
+		gradient.addColorStop(0, 'rgb(' + adjustColor(corners[0]).join(',') + ')');
+		for (var i = 0, il = rightLights.length; i < il; i++) {
+			gradient.addColorStop(i * stopSize + stopSize/2, 'rgb(' + adjustColor(rightLights[i]).join(',') + ')');
+		}
+		gradient.addColorStop(1.0, 'rgb(' + adjustColor(corners[1]).join(',') + ')');
+		lightsContext.fillStyle = gradient;
+		lightsContext.fillRect(size+width, size, size+width+size, height);
+
+
+		// bottom
+		gradient = context.createLinearGradient(size, size+height, size+width, size+height);
+		gradient.addColorStop(0, 'rgb(' + adjustColor(corners[2]).join(',') + ')');
+		for (var i = 0, il = bottomLights.length; i < il; i++) {
+			gradient.addColorStop(i * stopSize + stopSize/2, 'rgb(' + adjustColor(bottomLights[i]).join(',') + ')');
+		}
+		gradient.addColorStop(1.0, 'rgb(' + adjustColor(corners[1]).join(',') + ')');
+		lightsContext.fillStyle = gradient;
+		lightsContext.fillRect(size, size+height, width, size);
+
+		// left
+		gradient = context.createLinearGradient(size, size, size, size+height);
+		gradient.addColorStop(0, 'rgb(' + adjustColor(corners[3]).join(',') + ')');
+		for (var i = 0, il = leftLights.length; i < il; i++) {
+			gradient.addColorStop(i * stopSize + stopSize/2, 'rgb(' + adjustColor(leftLights[i]).join(',') + ')');
+		}
+		gradient.addColorStop(1.0, 'rgb(' + adjustColor(corners[2]).join(',') + ')');
+		lightsContext.fillStyle = gradient;
+		lightsContext.fillRect(0, size, size, height);
+
+		// corners
+
+		// top right
+		lightsContext.fillStyle = 'rgb(' + adjustColor(corners[0]).join(',') + ')';
+		lightsContext.fillRect(width+size, 0, size+width+size, size);
+
+		// bottom right
+		lightsContext.fillStyle = 'rgb(' + adjustColor(corners[1]).join(',') + ')';
+		lightsContext.fillRect(width+size, size+height, size+width+size, size+height+size);
+
+		// bottom left
+		lightsContext.fillStyle = 'rgb(' + adjustColor(corners[2]).join(',') + ')';
+		lightsContext.fillRect(0, size+height, size, size+height+size);
+
+		// top left
+		lightsContext.fillStyle = 'rgb(' + adjustColor(corners[3]).join(',') + ')';
+		lightsContext.fillRect(0, 0, size, size);
+
+
+
+
+
+		$(lightsCanvas)
+			.css('position','absolute')
+			.css('top',-size)
+			.css('left',-size)
+			.appendTo(base);
+	}
+
+	function addGlow(color, g) {
+		g.addColorStop(0.0, 'rgba(' + color.join(',') + ',0)');
+		g.addColorStop(1.0, 'rgba(' + color.join(',') + ',1)');
+		return g;
+	}
+
+
+
+
+	function getMidColors(canvas, context, blocks, blockDepth, side) {
+		var width = canvas.width,
+			height = canvas.height,
+			blockHeight = (side == 'top' || side == 'bottom') ? blockDepth : Math.ceil(height / blocks), // height of the analyzed block
+			blockWidth = (side == 'top' || side == 'bottom') ? Math.ceil(width / blocks) : blockDepth,
+			result = [],
+			imgdata,
+			i;
+
+		if (side == 'top' || side == 'bottom') {
+			for (i = 0; i < blocks; i++) {
+				try {
+					imgdata = context.getImageData(i*blockWidth, (side == 'top') ? 0 : height - blockHeight , blockWidth, blockHeight);
+					result.push( 
+						calcMidColor(imgdata.data)
+					);
+				} catch (e) {
+					console.log(e);
+				}
+			}
+		} else {
+
+			for (i = 0; i < blocks; i++) {
+				try {
+					imgdata = context.getImageData( (side == 'right') ? width - blockWidth : 0, i*blockHeight, blockWidth, blockHeight);
+					result.push( 
+						calcMidColor(imgdata.data)
+					);
+				} catch (e) {
+					console.log(e);
+				}
+
+			}
+		}
+
+
+		return result;
+	}
+
+	function averageColor(c1,c2) {
+		var result = 
+			[(c1[0] + c2[0]) / 2, 
+			 (c1[1] + c2[1]) / 2,  
+			 (c1[2] + c2[2]) / 2];
+			 
+		return result;
+	}
+
+	// average color for a block
+	function calcMidColorVertical(data, from, to) {
+		var result = [0, 0, 0];
+		var totalPixels = (to - from) / 4;
+
+		for (var i = from; i <= to; i += 4) {
+			result[0] += data[i];
+			result[1] += data[i + 1];
+			result[2] += data[i + 2];
+		}
+
+		result[0] = Math.round(result[0] / totalPixels);
+		result[1] = Math.round(result[1] / totalPixels);
+		result[2] = Math.round(result[2] / totalPixels);
+
+		return result;
+	}
+
+	// average color for a block
+	function calcMidColor(data) {
+		var result = [0, 0, 0];
+		var totalPixels = data.length;
+
+		for (var i = 0; i < totalPixels; i += 4) {
+			result[0] += data[i];
+			result[1] += data[i + 1];
+			result[2] += data[i + 2];
+		}
+
+		result[0] = Math.round(result[0] / totalPixels);
+		result[1] = Math.round(result[1] / totalPixels);
+		result[2] = Math.round(result[2] / totalPixels);
+
+		return result;
+	}
+
+	function adjustColor(color) {
+		//if (color[0] <= 2 && color[2] <= 2 && color[3] <= 2)
+		//	return color;
+
+		color = rgb2hsv(color);
+		color[1] = Math.min(100, color[1] * 1.2); //1.4); // saturation
+		color[2] = 80; //Math.min(100, color[2] * 2.7); //2.7); // brightness
+		return hsv2rgb(color);
+	}
+
+	function rgb2hsv(color) {
+		var r = color[0] / 255,
+			g = color[1] / 255,
+			b = color[2] / 255,
+
+			x, val, d1, d2, hue, sat, val;
+
+		x = Math.min(Math.min(r, g), b);
+		val = Math.max(Math.max(r, g), b);
+		//if (x == val)
+		//	throw Error('h is undefined');
+
+		d1 = (r == x) ? g-b : ((g == x) ? b-r : r-g);
+		d2 = (r == x) ? 3 : ((g == x) ? 5 : 1);
+
+		hue = Math.floor((d2 - d1 / (val - x)) * 60) % 360;
+		sat = Math.floor(((val - x) / val) * 100);
+		val = Math.floor(val * 100);
+		return [hue, sat, val];
+	}
+
+	/**
+	 * Convers HSV color to RGB model
+	 * @param {Number[]} RGB color
+	 * @return {Number[]} HSV color
+	 */
+	function hsv2rgb(color) {
+		var h = color[0],
+			s = color[1],
+			v = color[2];
+
+		var r, g, a, b, c, s = s / 100, v = v / 100, h = h / 360;
+
+		if (s > 0) {
+			if (h >= 1) h=0;
+
+			h = 6 * h;
+			var f = h - Math.floor(h);
+			a = Math.round(255 * v * (1 - s));
+			b = Math.round(255 * v * (1 - (s * f)));
+			c = Math.round(255 * v * (1 - (s * (1 - f))));
+			v = Math.round(255 * v);
+
+			switch (Math.floor(h)) {
+				case 0: r = v; g = c; b = a; break;
+				case 1: r = b; g = v; b = a; break;
+				case 2: r = a; g = v; b = c; break;
+				case 3: r = a; g = b; b = v; break;
+				case 4: r = c; g = a; b = v; break;
+				case 5: r = v; g = a; b = b; break;
+			}
+
+			return [r || 0, g || 0, b || 0];
+
+		} else {
+			v = Math.round(v * 255);
+			return [v, v, v];
+		}
+	}
+
+})(mejs.$);
\ No newline at end of file