Mercurial > hg > env-test-daniele
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.$); |