Lately we can notice there is a slight change in YouTube, hard to notice but if you are fan of video effects then you should be able to notice the new change. I might be hard to notice but yes it’s there and a cool effect.
Not sure if it is noticeable in the above image but there is slight background effect in the video and let’s learn how to do it.
So, first we need to get into the basics of points that are needed and the flow how to make it. There are 3 things that we are interested in.
– First the video element
– We map the video element to a HTML canvas when it plays
– We average out the red, green and blue properties of the image that is mapped to the canvas
– Voila, then we set the border color of the video player to that
Here is a preview on jsfiddle that I worked on:
Well, you can mostly view the code directly on the fiddle below but let me explain it one by one. First on the HTML we created a div that wraps the actual player. I created the margin to 50 for the moment so it looks real but if the video is in different place for you the margin is not even needed. And extra css that is not even needed on some project that you might be working on.
Now comes the JS phase, I defined all the elements that are required to process during the playing of video.
1 2 3 4 |
let video = document.getElementById("video") let main_player = document.getElementById("main_player") let canvas = document.createElement('canvas'); let ctx = canvas.getContext('2d'); |
Then we assign the video description to the canvas we just virtually created, in future if they don’t allow to create virtually then we must assign a canvas somewhere or underneath the video player itself so it doesn’t get displayed to the end user.
1 2 3 4 |
video.addEventListener('loadedmetadata', function() { canvas.width = video.videoWidth; canvas.height = video.videoHeight; }); |
Now the main part is when the play event is called we request for frame from the video and then process the RGB parameters from the video by mapping it to the above canvas.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
video.addEventListener('play', function () { var $this = this; //cache (function loop() { if (!$this.paused && !$this.ended) { ctx.drawImage($this, 0, 0); var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); var data = imageData.data; var r = 0; var g = 0; var b = 0; for (var i = 0, l = data.length; i < l; i += 4) { r += data[i]; g += data[i+1]; b += data[i+2]; } r = Math.floor(r / (data.length / 4)); g = Math.floor(g / (data.length / 4)); b = Math.floor(b / (data.length / 4)); main_player.style["box-shadow"] = "0 0 50px 0 rgb("+[r,g,b].join(", ")+")" setTimeout(loop, 1000 / 5); // drawing at 5fps so we dont make it heavy } })(); }, 0); |
Now the magic is ready, above code mapped the video image data to canvas, then we loop through all UInt8 byte array representing R, G, B and A properties and we are ignoring the opacity property. Then we average out by the total number of data by 4 which is the total pixels in the image. Then with a simple box-shadow CSS property for the div, we are finally able to see the result after the playing. Looping is applied to request image data while the video is being played.
It’s so cool and simple with few lines of codes and YouTube has flawlessly implemented it on their platform.
Happy coding!!