annotate johndyer-mediaelement-13fa20a/src/js/mep-feature-backlight.js @ 25:4a4bd554b4c1 tip

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