I am trying to draw the video frames on canvas in react basically something which is already done in vanilla java script into react little differently.
vanilla js code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<video id="video" width="800" src="./media/video.mp4" autoplay muted loop></video>
<canvas id="output-canvas" width="800" height="450"></canvas>
</div>
<script>
let video, c1, ctx1, c_tmp, ctx_tmp;
function init() {
video = document.getElementById('video');
c1 = document.getElementById('output-canvas');
ctx1 = c1.getContext('2d');
c_tmp = document.createElement('canvas');
c_tmp.setAttribute('width', 800);
c_tmp.setAttribute('height', 450);
ctx_tmp = c_tmp.getContext('2d');
video.addEventListener('play', computeFrame);
}
function computeFrame() {
ctx_tmp.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
let frame = ctx_tmp.getImageData(0, 0, video.videoWidth, video.videoHeight);
ctx1.putImageData(frame, 0, 0);
setTimeout(computeFrame, 0);
}
document.addEventListener("DOMContentLoaded", () => {
init();
});
</script>
</body>
</html>
Now my same try for implementation in react is below
import logo from './logo.svg';
import './App.css';
import React from 'react';
import {useRef,useState, useEffect} from 'react';
import gvideo from './assets/videos/gvid.mp4'
function App() {
const video = useRef(null);
const c1= useRef(null);
const c2= useRef(null);
const [playerState, setPlayerState] = useState({
isPlaying: false,
progress: 0,
speed: 1,
isMuted: false,
});
let width= video.clientWidth;
let height= video.clientHeight;
let ctx= c2.current.getContext('2d');
function drawVid(){
ctx.drawImage(video,0,0,width,height);
let frame= ctx.getImageData(0,0,width,height);
for(let i=0; i<frame.data.length; i =4){
let r= frame.data[i];
let g= frame.data[i 1];
let b= frame.data[i 2];
}
requestAnimationFrame(drawVid);
}
useEffect(() => {
// drawVid()
});
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<video ref={video} id="my_video" src={gvideo} height="300" width="600" autoPlay loop muted ></video>
<canvas style={{display:"none"}} ref={c1} id="c1" width="160" height="96"></canvas>
<canvas ref={c2} id="c2" width="300" height="400"></canvas>
<p>
Edit {playerState.isPlaying} <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
kindly someone guide me , I have to implement something similar to this i.e. chroma keying
CodePudding user response:
Bascially you have done right, but pay attention:
- You should use
video.current
instead ofvideo
in yourfunction drawVid
, and in thewidth/height
inititaion. Check Hooks Reference let ctx= c2.current.getContext('2d');
may cause error at first, because the c2.current will be null until the canvas really mounted. Try put it insidefunction drawId
and make some protection like
if(!c2.current){
// check if video dom is ready
requestNextAnimationFrame(drawId)
}
And it's better to do same protection for video
if(!video.current){
// check if video dom is ready
requestNextAnimationFrame(drawId)
}