comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:032bc65ebafc
1 (function($) {
2
3 $.extend(mejs.MepDefaults, {
4 backlightBackground: [0,0,0],
5 backlightHorizontalLights: 5,
6 backlightVerticalLights: 5,
7 backlightSize: 50,
8 backlightTimeout: 200
9 });
10
11
12
13 MediaElementPlayer.prototype.buildbacklight = function(player, controls, layers, media) {
14 if (!player.isVideo)
15 return;
16
17 //http://www.splashnology.com/blog/html5/382.html
18
19 var
20 mediaContainer = player.container.find('.mejs-mediaelement').parent(),
21 border = $('<div class="mejs-border"></div>')
22 .prependTo(mediaContainer)
23 .css('position','absolute')
24 .css('top','-10px')
25 .css('left','-10px')
26 .css('border','solid 10px #010101')
27 .width(player.width).height(player.height),
28 glowBase = $('<div class="mejs-backlight-glow"></div>')
29 .prependTo(mediaContainer)
30 .css('position','absolute')
31 .css('display','none')
32 .css('top',0)
33 .css('left',0)
34 .width(player.width).height(player.height),
35 base = $('<div class="mejs-backlight"></div>')
36 .prependTo(mediaContainer)
37 .css('position','absolute')
38 .css('top',0)
39 .css('left',0)
40 .width(player.width).height(player.height),
41
42 i,
43 copyCanvas = document.createElement('canvas'),
44 copyContext = copyCanvas.getContext('2d'),
45 pixels,
46 keepUpdating = true,
47 isActive = true,
48 timer = null,
49 glowCanvas = document.createElement('canvas'),
50 glowContext = glowCanvas.getContext('2d'),
51 size = player.options.backlightSize,
52 backgroundColor = player.options.backlightBackground,
53 gradient,
54 width = player.width,
55 height = player.height;
56
57 // set sizes
58 copyCanvas.width = width;
59 copyCanvas.height = height;
60 glowCanvas.width = width + size + size;
61 glowCanvas.height = height + size + size;
62
63 // draw glow overlay
64 // top
65 gradient = addGlow(backgroundColor,glowContext.createLinearGradient(size, size, size, 0));
66 glowContext.fillStyle = gradient;
67 glowContext.fillRect(size, size, width, -size);
68
69 // tr
70 gradient = addGlow(backgroundColor,glowContext.createRadialGradient(width+size, size, 0, width+size, size, size));
71 glowContext.fillStyle = gradient;
72 glowContext.fillRect(width+size, size, size, -size);
73
74 // right
75 gradient = addGlow(backgroundColor,glowContext.createLinearGradient(width+size, size, width+size+size, size));
76 glowContext.fillStyle = gradient;
77 glowContext.fillRect(width+size, size, size, height);
78
79 // br
80 gradient = addGlow(backgroundColor,glowContext.createRadialGradient(width+size, height+size, 0, width+size, height+size, size));
81 glowContext.fillStyle = gradient;
82 glowContext.fillRect(width+size, height+size, size, size);
83
84 // bottom
85 var gradient = addGlow(backgroundColor,glowContext.createLinearGradient(size, size+height, size, size+height+size));
86 glowContext.fillStyle = gradient;
87 glowContext.fillRect(size, size+height, width, size);
88
89 // bl
90 gradient = addGlow(backgroundColor,glowContext.createRadialGradient(size, height+size, 0, size, height+size, size));
91 glowContext.fillStyle = gradient;
92 glowContext.fillRect(0, height+size, size, size);
93
94 // left
95 gradient = addGlow(backgroundColor,glowContext.createLinearGradient(size, size, 0, size));
96 glowContext.fillStyle = gradient;
97 glowContext.fillRect(size, size, -size, height);
98
99 // tl
100 gradient = addGlow(backgroundColor,glowContext.createRadialGradient(size, size, 0, size, size, size));
101 glowContext.fillStyle = gradient;
102 glowContext.fillRect(0, 0, size, size);
103
104 $(glowCanvas)
105 .css('position','absolute')
106 .css('top',-size)
107 .css('left',-size)
108 .appendTo(glowBase);
109
110
111 // add toggle control
112 $('<div class="mejs-backlight-button mejs-backlight-active"><span></span></div>')
113 .appendTo(controls)
114 .click(function() {
115 if (isActive) {
116 delete timer;
117 timer = null;
118 base.hide();
119 glowBase.hide();
120 $(this)
121 .removeClass('mejs-backlight-active')
122 .addClass('mejs-backlight-inactive')
123 } else {
124 updateLights();
125 base.show();
126 glowBase.show();
127 $(this)
128 .removeClass('mejs-backlight-inactive')
129 .addClass('mejs-backlight-active')
130 }
131 isActive = !isActive;
132 });
133
134
135 // http://www.splashnology.com/blog/html5/382.html
136 function updateLights() {
137
138 // get a copy of video
139 copyContext.drawImage(media, 0, 0, media.width, media.height);
140
141 // create the gradient lights
142 addLights(base, copyCanvas, copyContext,
143 player.options.backlightVerticalLights,
144 player.options.backlightHorizontalLights,
145 player.options.backlightSize,
146 30);
147
148 if (keepUpdating && isActive) {
149 timer = setTimeout(updateLights, player.options.backlightTimeout);
150 }
151 }
152
153
154
155
156 //setTimeout(updateLights, timeOut);
157
158 media.addEventListener('play',function() {
159 if (isActive) {
160 keepUpdating = true;
161 updateLights();
162 glowBase.css('display','');
163 }
164 }, false);
165 media.addEventListener('pause',function() {
166 keepUpdating = false;
167 }, false);
168 media.addEventListener('ended',function() {
169 keepUpdating = false;
170 }, false);
171
172 };
173
174
175
176 function addLights(base, canvas, context, vBlocks, hBlocks, size, depth) {
177 base.empty();
178
179 var
180 lightsCanvas = document.createElement('canvas'),
181 lightsContext = lightsCanvas.getContext('2d'),
182 width = canvas.width,
183 height = canvas.height,
184 g,
185 topLights = getMidColors(canvas, context, hBlocks, depth, 'top'),
186 bottomLights = getMidColors(canvas, context, hBlocks, depth, 'bottom'),
187 leftLights = getMidColors(canvas, context, vBlocks, depth, 'left'),
188 rightLights = getMidColors(canvas, context, vBlocks, depth, 'right'),
189 corners = [],
190 stopSize = 0;
191
192 lightsCanvas.width = width + size + size;
193 lightsCanvas.height = height + size + size;
194 lightsContext.globalCompositeOperation = 'xor'; //'darker'; //'lighter';
195
196 // draw four gradients
197 // create corners
198 corners.push(averageColor(topLights[topLights.length-1], rightLights[0]) );
199 corners.push(averageColor(bottomLights[bottomLights.length-1], rightLights[rightLights.length-1]) );
200 corners.push(averageColor(bottomLights[0], leftLights[leftLights.length-1]) );
201 corners.push(averageColor(topLights[0], leftLights[0]) );
202
203 // top
204 stopSize = 1 / topLights.length;
205 gradient = context.createLinearGradient(size, size, width+size, size);
206 gradient.addColorStop(0, 'rgb(' + adjustColor(corners[3]).join(',') + ')');
207 for (var i = 0, il = topLights.length; i < il; i++) {
208 gradient.addColorStop(i * stopSize + stopSize/2, 'rgb(' + adjustColor(topLights[i]).join(',') + ')');
209 }
210 gradient.addColorStop(1.0, 'rgb(' + adjustColor(corners[0]).join(',') + ')');
211 lightsContext.fillStyle = gradient;
212 lightsContext.fillRect(size, 0, width, size);
213
214 // right
215 gradient = context.createLinearGradient(size+width, size, size+width, size+height);
216 gradient.addColorStop(0, 'rgb(' + adjustColor(corners[0]).join(',') + ')');
217 for (var i = 0, il = rightLights.length; i < il; i++) {
218 gradient.addColorStop(i * stopSize + stopSize/2, 'rgb(' + adjustColor(rightLights[i]).join(',') + ')');
219 }
220 gradient.addColorStop(1.0, 'rgb(' + adjustColor(corners[1]).join(',') + ')');
221 lightsContext.fillStyle = gradient;
222 lightsContext.fillRect(size+width, size, size+width+size, height);
223
224
225 // bottom
226 gradient = context.createLinearGradient(size, size+height, size+width, size+height);
227 gradient.addColorStop(0, 'rgb(' + adjustColor(corners[2]).join(',') + ')');
228 for (var i = 0, il = bottomLights.length; i < il; i++) {
229 gradient.addColorStop(i * stopSize + stopSize/2, 'rgb(' + adjustColor(bottomLights[i]).join(',') + ')');
230 }
231 gradient.addColorStop(1.0, 'rgb(' + adjustColor(corners[1]).join(',') + ')');
232 lightsContext.fillStyle = gradient;
233 lightsContext.fillRect(size, size+height, width, size);
234
235 // left
236 gradient = context.createLinearGradient(size, size, size, size+height);
237 gradient.addColorStop(0, 'rgb(' + adjustColor(corners[3]).join(',') + ')');
238 for (var i = 0, il = leftLights.length; i < il; i++) {
239 gradient.addColorStop(i * stopSize + stopSize/2, 'rgb(' + adjustColor(leftLights[i]).join(',') + ')');
240 }
241 gradient.addColorStop(1.0, 'rgb(' + adjustColor(corners[2]).join(',') + ')');
242 lightsContext.fillStyle = gradient;
243 lightsContext.fillRect(0, size, size, height);
244
245 // corners
246
247 // top right
248 lightsContext.fillStyle = 'rgb(' + adjustColor(corners[0]).join(',') + ')';
249 lightsContext.fillRect(width+size, 0, size+width+size, size);
250
251 // bottom right
252 lightsContext.fillStyle = 'rgb(' + adjustColor(corners[1]).join(',') + ')';
253 lightsContext.fillRect(width+size, size+height, size+width+size, size+height+size);
254
255 // bottom left
256 lightsContext.fillStyle = 'rgb(' + adjustColor(corners[2]).join(',') + ')';
257 lightsContext.fillRect(0, size+height, size, size+height+size);
258
259 // top left
260 lightsContext.fillStyle = 'rgb(' + adjustColor(corners[3]).join(',') + ')';
261 lightsContext.fillRect(0, 0, size, size);
262
263
264
265
266
267 $(lightsCanvas)
268 .css('position','absolute')
269 .css('top',-size)
270 .css('left',-size)
271 .appendTo(base);
272 }
273
274 function addGlow(color, g) {
275 g.addColorStop(0.0, 'rgba(' + color.join(',') + ',0)');
276 g.addColorStop(1.0, 'rgba(' + color.join(',') + ',1)');
277 return g;
278 }
279
280
281
282
283 function getMidColors(canvas, context, blocks, blockDepth, side) {
284 var width = canvas.width,
285 height = canvas.height,
286 blockHeight = (side == 'top' || side == 'bottom') ? blockDepth : Math.ceil(height / blocks), // height of the analyzed block
287 blockWidth = (side == 'top' || side == 'bottom') ? Math.ceil(width / blocks) : blockDepth,
288 result = [],
289 imgdata,
290 i;
291
292 if (side == 'top' || side == 'bottom') {
293 for (i = 0; i < blocks; i++) {
294 try {
295 imgdata = context.getImageData(i*blockWidth, (side == 'top') ? 0 : height - blockHeight , blockWidth, blockHeight);
296 result.push(
297 calcMidColor(imgdata.data)
298 );
299 } catch (e) {
300 console.log(e);
301 }
302 }
303 } else {
304
305 for (i = 0; i < blocks; i++) {
306 try {
307 imgdata = context.getImageData( (side == 'right') ? width - blockWidth : 0, i*blockHeight, blockWidth, blockHeight);
308 result.push(
309 calcMidColor(imgdata.data)
310 );
311 } catch (e) {
312 console.log(e);
313 }
314
315 }
316 }
317
318
319 return result;
320 }
321
322 function averageColor(c1,c2) {
323 var result =
324 [(c1[0] + c2[0]) / 2,
325 (c1[1] + c2[1]) / 2,
326 (c1[2] + c2[2]) / 2];
327
328 return result;
329 }
330
331 // average color for a block
332 function calcMidColorVertical(data, from, to) {
333 var result = [0, 0, 0];
334 var totalPixels = (to - from) / 4;
335
336 for (var i = from; i <= to; i += 4) {
337 result[0] += data[i];
338 result[1] += data[i + 1];
339 result[2] += data[i + 2];
340 }
341
342 result[0] = Math.round(result[0] / totalPixels);
343 result[1] = Math.round(result[1] / totalPixels);
344 result[2] = Math.round(result[2] / totalPixels);
345
346 return result;
347 }
348
349 // average color for a block
350 function calcMidColor(data) {
351 var result = [0, 0, 0];
352 var totalPixels = data.length;
353
354 for (var i = 0; i < totalPixels; i += 4) {
355 result[0] += data[i];
356 result[1] += data[i + 1];
357 result[2] += data[i + 2];
358 }
359
360 result[0] = Math.round(result[0] / totalPixels);
361 result[1] = Math.round(result[1] / totalPixels);
362 result[2] = Math.round(result[2] / totalPixels);
363
364 return result;
365 }
366
367 function adjustColor(color) {
368 //if (color[0] <= 2 && color[2] <= 2 && color[3] <= 2)
369 // return color;
370
371 color = rgb2hsv(color);
372 color[1] = Math.min(100, color[1] * 1.2); //1.4); // saturation
373 color[2] = 80; //Math.min(100, color[2] * 2.7); //2.7); // brightness
374 return hsv2rgb(color);
375 }
376
377 function rgb2hsv(color) {
378 var r = color[0] / 255,
379 g = color[1] / 255,
380 b = color[2] / 255,
381
382 x, val, d1, d2, hue, sat, val;
383
384 x = Math.min(Math.min(r, g), b);
385 val = Math.max(Math.max(r, g), b);
386 //if (x == val)
387 // throw Error('h is undefined');
388
389 d1 = (r == x) ? g-b : ((g == x) ? b-r : r-g);
390 d2 = (r == x) ? 3 : ((g == x) ? 5 : 1);
391
392 hue = Math.floor((d2 - d1 / (val - x)) * 60) % 360;
393 sat = Math.floor(((val - x) / val) * 100);
394 val = Math.floor(val * 100);
395 return [hue, sat, val];
396 }
397
398 /**
399 * Convers HSV color to RGB model
400 * @param {Number[]} RGB color
401 * @return {Number[]} HSV color
402 */
403 function hsv2rgb(color) {
404 var h = color[0],
405 s = color[1],
406 v = color[2];
407
408 var r, g, a, b, c, s = s / 100, v = v / 100, h = h / 360;
409
410 if (s > 0) {
411 if (h >= 1) h=0;
412
413 h = 6 * h;
414 var f = h - Math.floor(h);
415 a = Math.round(255 * v * (1 - s));
416 b = Math.round(255 * v * (1 - (s * f)));
417 c = Math.round(255 * v * (1 - (s * (1 - f))));
418 v = Math.round(255 * v);
419
420 switch (Math.floor(h)) {
421 case 0: r = v; g = c; b = a; break;
422 case 1: r = b; g = v; b = a; break;
423 case 2: r = a; g = v; b = c; break;
424 case 3: r = a; g = b; b = v; break;
425 case 4: r = c; g = a; b = v; break;
426 case 5: r = v; g = a; b = b; break;
427 }
428
429 return [r || 0, g || 0, b || 0];
430
431 } else {
432 v = Math.round(v * 255);
433 return [v, v, v];
434 }
435 }
436
437 })(mejs.$);