I have React class with two main elements. Canvas and video. I get video stream and render it at 30fps to canvas.
class GetImage extends Component {
constructor() {
super();
this.constraints = {
video: {
width: { ideal: 2048 },
height: { ideal: 1080 },
facingMode: {
exact: 'environment'
}
}
}
}
componentDidMount() {
setVideo(this.video, this.constraints, this.readyToPlayVideo)
}
capture = () => {
const { video } = this
let canvas = document.createElement('canvas')
canvas.width = video.videoWidth
canvas.height = video.videoHeight
let context = canvas.getContext('2d')
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(this.video, 0, 0, canvas.width, canvas.height)
this.setState({ capture: canvas.toDataURL('image/jpeg') })
stopVideo()
}
readyToPlayVideo = () => {
const { canvas, video } = this
const { offsetHeight, offsetWidth } = video
const ctx = canvas.getContext('2d')
ctx.canvas.setAttribute('height', offsetHeight)
ctx.canvas.setAttribute('width', offsetWidth)
const timeout = 1000 / 30 // drawing at 30fps
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
let _listener = () => {
(function loop() {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.drawImage(video, 0, 0)
setTimeout(loop, timeout)
})()
}
_listener();
}
retake = () =>
this.setState({ capture: null },
() => {
setVideo(this.video, this.constraints, this.readyToPlayVideo, this.handleError)
}
)
render() {
return (
<div>
<video
style={{ visibility: 'hidden'}}
ref={video => (this.video = video)}
playsInline
autoPlay
/>
<canvas ref={canvas => (this.canvas = canvas)}/>
</div>
)
}
}
So far so good. But I faced a problem with mobile Safari. Looks like it keep every Canvas object ever created in memory.
After several pictures was taken Safari crashes with "out of memory". I already do clearRect before rendering a new image, but it doesn't help.
There are a couple of issues to address here. Firstly, you seem to have a circular reference in your loop
function; you are calling the function within the function.
Because of this, the autoplay the video (when rendering) won't stop .. causing the 'out of memory' error.
Also , I think best practice would be to create a componentDidUnmount
function that destroys the video (when no longer needed). Use .dispose
to destroy the video.
Hope this helps
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With