javascript - 如何在 React 的画布上连续流式传输视频?
问题描述
基本上,我试图在 React 的上下文中使用https://github.com/cozmo/jsQR。但是,canvas 仅在组件挂载时捕获视频流。如何在整个过程中使用反应画布连续流式传输视频?
import React, { Component } from "react";
import jsQR from "jsqr";
class WebcamStream extends Component {
constructor(props) {
super(props);
this.videoTag = React.createRef();
this.canvas = React.createRef();
this.tick = this.tick.bind(this);
}
componentDidMount() {
// getting access to webcam
navigator.mediaDevices
.getUserMedia({ video: { facingMode: "environment" } })
.then(stream => {
const video = this.videoTag.current;
video.srcObject = stream;
video.setAttribute("playsinline", true);
video.play();
requestAnimationFrame(this.tick);
});
}
componentDidUpdate() {}
drawLine(begin, end, color) {
const canvasElement = this.canvas.current;
const canvas = canvasElement.getContext("2d");
canvas.beginPath();
canvas.moveTo(begin.x, begin.y);
canvas.lineTo(end.x, end.y);
canvas.lineWidth = 4;
canvas.strokeStyle = color;
canvas.stroke();
}
tick() {
const video = this.videoTag.current;
const checkVideoState = setInterval(() => {
if (video.readyState === video.HAVE_ENOUGH_DATA) {
clearInterval(checkVideoState);
const canvasElement = this.canvas.current;
const canvas = canvasElement.getContext("2d");
canvasElement.height = video.videoHeight;
canvasElement.width = video.videoWidth;
canvas.drawImage(
video,
0,
0,
canvasElement.width,
canvasElement.height
);
let imageData = canvas.getImageData(
0,
0,
canvasElement.width,
canvasElement.height
);
console.log(imageData);
var code = jsQR(imageData.data, imageData.width, imageData.height);
if (code) {
console.log("CODE");
this.drawLine(
code.location.topLeftCorner,
code.location.topRightCorner,
"#FF3B58"
);
this.drawLine(
code.location.topRightCorner,
code.location.bottomRightCorner,
"#FF3B58"
);
this.drawLine(
code.location.bottomRightCorner,
code.location.bottomLeftCorner,
"#FF3B58"
);
this.drawLine(
code.location.bottomLeftCorner,
code.location.topLeftCorner,
"#FF3B58"
);
} else {
}
}
}, 3000);
}
render() {
return (
<div>
<video ref={this.videoTag} width="400" height="400" autoPlay />
<canvas ref={this.canvas} />
</div>
);
}
}
export default WebcamStream;
解决方案
requestAnimationFrame()
好的,我意识到这就像在方法内部再次调用一样简单tick()
。
import React, { Component } from "react";
import jsQR from "jsqr";
class WebcamStream extends Component {
constructor(props) {
super(props);
this.state = {
isVideoLoading: true
};
this.videoTag = React.createRef();
this.canvas = React.createRef();
this.tick = this.tick.bind(this);
}
componentDidMount() {
// getting access to webcam
navigator.mediaDevices
.getUserMedia({ video: { facingMode: "environment" } })
.then(stream => {
const video = this.videoTag.current;
video.srcObject = stream;
video.setAttribute("playsinline", true);
video.play();
requestAnimationFrame(this.tick);
});
}
drawLine(begin, end, color) {
const canvasElement = this.canvas.current;
const canvas = canvasElement.getContext("2d");
canvas.beginPath();
canvas.moveTo(begin.x, begin.y);
canvas.lineTo(end.x, end.y);
canvas.lineWidth = 4;
canvas.strokeStyle = color;
canvas.stroke();
}
tick() {
const video = this.videoTag.current;
const checkVideoState = setInterval(() => {
if (video.readyState === video.HAVE_ENOUGH_DATA) {
clearInterval(checkVideoState);
this.setState({ isVideoLoading: false });
const canvasElement = this.canvas.current;
const canvas = canvasElement.getContext("2d");
canvasElement.height = video.videoHeight;
canvasElement.width = video.videoWidth;
canvas.drawImage(
video,
0,
0,
canvasElement.width,
canvasElement.height
);
let imageData = canvas.getImageData(
0,
0,
canvasElement.width,
canvasElement.height
);
var code = jsQR(imageData.data, imageData.width, imageData.height);
if (code) {
this.drawLine(
code.location.topLeftCorner,
code.location.topRightCorner,
"#FF3B58"
);
this.drawLine(
code.location.topRightCorner,
code.location.bottomRightCorner,
"#FF3B58"
);
this.drawLine(
code.location.bottomRightCorner,
code.location.bottomLeftCorner,
"#FF3B58"
);
this.drawLine(
code.location.bottomLeftCorner,
code.location.topLeftCorner,
"#FF3B58"
);
}
requestAnimationFrame(this.tick);
}
}, 1000);
}
render() {
const { isVideoLoading } = this.state;
return (
<div>
<video
ref={this.videoTag}
width="400"
height="400"
autoPlay
style={{ display: "none" }}
/>
{!isVideoLoading && <canvas ref={this.canvas} />}
{isVideoLoading && <p>Please wait while we load the video stream.</p>}
</div>
);
}
}
export default WebcamStream;
推荐阅读
- c++ - 没有 void_t 的 SFINAE(可能是模板专业化问题)
- python - BeautifulSoup 不采用完整的 HTML 代码
- c++ - 将音频流写入循环缓冲区但分段错误读取值
- button - 单击按钮时打印图像
- android - 如何在 android 中使用 onSelectedDayChange() 为 CalendarView 显示月份名称
- swift - 结构体的 Swift 枚举
- .net - 从 Xamarin 项目中的文件夹中获取所有对象
- python - 如何在OpenCV中合并两个不同颜色的位掩码
- react-native - 如何在 React Native 中使用 AsyncStorage 数据更新状态挂钩?
- hadoop - 是否可以将 orc 托管表位置或文件用于外部表?