Day 19— Play with real time video

What I learned from JavaScript 30(Course Web — https://javascript30.com/)

Coding on Github


Play with real time video, such as take a photo from video, add visual effect.


Play real time video

Get the video
En-MDN: getUserMedia

navigator.mediaDevices.getUserMedia({ video: true, audio: false })
 .then(localMediaStream => {
 console.log(localMediaStream);
 video.src = window.URL.createObjectURL(localMediaStream);
 video.play();
 })
 .catch(err => {
 console.error(`OH NO!!!`, err);
 });

Paint to canvas

Get the video’s size and use to canvas:

const video = document.querySelector(‘.player’);//refers to <video> tag.
const width = video.videoWidth;
const height = video.videoHeight;
const canvas = document.querySelector(‘.photo’);//refers to <canvas> tag.
const ctx = canvas.getContext(‘2d’);
canvas.width = width;
canvas.height = height;

Set frequency of painting:

setInterval(() => {ctx.drawImage(video, 0, 0, width, height);},10)

Automatically paint:
Put all codes above into a function (may called ‘paintToCanavas’), and add an listener to video’s play event.

video.addEventListener(‘canplay’, paintToCanavas);

En-MDN:canvas.drawImage
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage

Take photo from video

Get the photo data (base 64)

const data = canvas.toDataURL(‘image/jpeg’);

Create a link for it

const link = document.createElement(‘a’);
link.href = data;
link.innerHTML = `<img src=”${data}” alt=”Handsome Man” />`;//make it visual
strip.insertBefore(link, strip.firsChild);//strip is the div to put these links. insertBefore make the newest taken one be the first link seen on the screen.

Make it download-able

link.setAttribute(‘download’, ‘handsome’);//’handsome’ is the file name for the stored img.

Make effect to video

Do it within the setInterval function.

Take the pixels out:

let pixels = ctx.getImageData(0, 0, width, height);

Play with the effect function with pixel data:

pixels = redEffect(pixels);

Put them back:

ctx.putImageData(pixels, 0, 0);

Here are 3 kinds of effect

Color effect

Adjust the bold number to generate different color effect:

function redEffect(pixels) {
 for(let i = 0; i < pixels.data.length; i+=4) {
 pixels.data[i + 0] = pixels.data[i + 0] + 200; // RED
 pixels.data[i + 1] = pixels.data[i + 1] — 50; // GREEN
 pixels.data[i + 2] = pixels.data[i + 2] * 0.5; // Blue
 }
 return pixels;
}

Split effect

Adjust the bold number to make different split effect.

function rgbSplit(pixels) {
 for(let i = 0; i < pixels.data.length; i+=4) {
 pixels.data[i — 150] = pixels.data[i + 0]; // RED
 pixels.data[i + 500] = pixels.data[i + 1]; // GREEN
 pixels.data[i — 550] = pixels.data[i + 2]; // Blue
 }
 return pixels;
}

Greenscreen
Put some range input bar in html to custom effect:

<label for=”rmin”>Red Min:</label>
<input type=”range” min=0 max=255 name=”rmin”>

Select the bars and do something:

function greenScreen(pixels) {
 const levels = {};
document.querySelectorAll(‘.rgb input’).forEach((input) => {
 levels[input.name] = input.value;
 });
for (i = 0; i < pixels.data.length; i = i + 4) {
 red = pixels.data[i + 0];
 green = pixels.data[i + 1];
 blue = pixels.data[i + 2];
 alpha = pixels.data[i + 3];
if (red >= levels.rmin
 && green >= levels.gmin
 && blue >= levels.bmin
 && red <= levels.rmax
 && green <= levels.gmax
 && blue <= levels.bmax) {
 // take it out!
 pixels.data[i + 3] = 0;
 }
 }return pixels;
}

Or if do not allow to custom, just skip the selection and loop part.