如何使用 react js 组件在网页上流式传输网络摄像头提要?



我是 reactJS 的新手,并试图构建一个组件。

我想构建一个基本的实用程序,其中我有一个显示实时网络摄像头源的视频组件,并且会有一个捕获按钮,用于捕获源的快照并将其存储到磁盘。我希望它位于单个组件中(视频源 + 捕获按钮)

此代码在浏览器中流式传输提要,但我希望它在组件中,

<body>
<div id="container">
<video autoplay="true" id="videoElement">
</video>
</div>
<script>
var video = document.querySelector("#videoElement");
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;
if (navigator.getUserMedia) {       
navigator.getUserMedia({video: true}, handleVideo, videoError);
}
function handleVideo(stream) {
video.src = window.URL.createObjectURL(stream);
}
function videoError(e) {}
</script>
</body>
</html>

这工作正常,但不是它不是一个组件。

我尝试在 reaact js 中遵循,但它不起作用:

<body>
<div id="container">
</div>
<script type="text/jsx">
var MyComponent = React.createClass({
handleVideo: function(stream) {
video.src = window.URL.createObjectURL(stream);
},
videoError: function() {
},
render: function() {
var video = document.querySelector("#videoElement");
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;
if (navigator.getUserMedia) {       
navigator.getUserMedia({video: true}, this.handleVideo, this.videoError);
}
return <div>
<video autoplay="true" id="videoElement">
</video>
</div>;
}
});
React.render( <MyComponent />, document.getElementById('container'));
</script>
</body>

错误在句柄视频()

引用错误: 未定义视频。

我对错误的理解是,

由于视频标签稍后部分(作为回报),因此它试图在 handleVideo 函数中的定义之前使用。 我很困惑如何使这项工作。

谢谢!

关于 React 组件的工作方式,有几件事需要了解。 首先根据 React 文档:

render() 函数应该是纯的,这意味着它不会修改 组件状态,每次调用时都返回相同的结果, 并且它不直接与浏览器交互。

您应该将初始化视频元素移动到备用生命周期方法(如componentDidMount),以确保它只初始化一次。

其次,您很少需要直接与 DOM 交互。 在这种情况下,我们可以使用组件的内部状态来管理视频流的 src 属性,确保它仅在流初始化后更新。

下面是一个可能有效的更新组件:

var MyComponent = React.createClass({
getInitialState: function(){
return { videoSrc: null }
},
componentDidMount: function(){
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;
if (navigator.getUserMedia) {
navigator.getUserMedia({video: true}, this.handleVideo, this.videoError);
}
},
handleVideo: function(stream) {
// Update the state, triggering the component to re-render with the correct stream
this.setState({ videoSrc: window.URL.createObjectURL(stream) });
},
videoError: function() {
},
render: function() {
return <div>
<video src={this.state.videoSrc} autoPlay="true" />
</div>;
}
});

答案中发布的某些代码已被弃用,可能不再适用于所有浏览器。
我创建了一个使用最新语法的新 React 应用程序。 它非常简单明了。我希望它能帮助某人:)

class AppStreamCam extends React.Component {
constructor(props) {
super(props);
this.streamCamVideo= this.streamCamVideo.bind(this)
}
streamCamVideo() {
var constraints = { audio: true, video: { width: 1280, height: 720 } };
navigator.mediaDevices
.getUserMedia(constraints)
.then(function(mediaStream) {
var video = document.querySelector("video");
video.srcObject = mediaStream;
video.onloadedmetadata = function(e) {
video.play();
};
})
.catch(function(err) {
console.log(err.name + ": " + err.message);
}); // always check for errors at the end.
}
render() {
return (
<div>
<div id="container">
<video autoPlay={true} id="videoElement" controls></video>
</div>
<br/>
<button onClick={this.streamCamVideo}>Start streaming</button>
</div>
);
}
}

这是我关于它的 Medium 文章:
如何创建一个 React 应用程序来流式传输您的网络摄像头 |基础、初级

如果有帮助,别忘了鼓掌:)

最后,这是工作示例的 github 存储库: 基本网络摄像头流光

您的handleVideo方法引用video,但您没有在任何handleVideo可以看到它的地方定义该变量。 相反,您可以在render中定义它:

var video = document.querySelector("#videoElement");

所以这是你的第一个问题,但这不是你真正的问题。 你真正的问题是,在React-land中,你想避免document.anything(getElementByIdgetByTagAndClassNamequerySelector等)。 这是因为 React 使用虚拟 DOM,如果你在引用实际的 DOM 元素时不小心,这些引用很快就会变坏(因为虚拟 DOM 在render后替换了实际的 DOM)。

解决方案是使用 React 自己的替代技术:refs。 它们更容易通过示例解释,因此以下是使用refs修复的代码:

handleVideo: function(stream) {
// KEY CHANGE #1
this.refs.video.src = window.URL.createObjectURL(stream);
},
render: function() {
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;
if (navigator.getUserMedia) {       
navigator.getUserMedia({video: true}, this.handleVideo, this.videoError);
}
return <div>
{{/* KEY CHANGE #2 */}}
<video autoplay="true" id="videoElement" ref="video">
</video>
</div>;

换句话说,如果您将ref="something"属性添加到您在render函数中返回的任何元素,则可以通过引用this.refs.something来引用 (React) 代码中的其他任何位置。

还有其他方法可以使用refs(例如,您可以传递函数),但这超出了这个问题的范围,所以我建议您阅读 React 文档以获取refs

https://facebook.github.io/react/docs/refs-and-the-dom.html

编辑

正如 Jordan Burnett 的回答所强调的那样,React 和正常的 JS DOM 工作之间还有其他重要的区别。 同样,解释所有这些内容超出了这个问题的范围,但我强烈建议您阅读:

https://facebook.github.io/react/docs/react-component.html

学习适当的方法来覆盖以执行 DOM 交互工作(例如,在非 React 组件上绑定事件处理程序)。

这是AG_HIHI作为功能组件编写的解决方案。我删除了开始按钮,而是在完成后立即启动。将 AppStreamCam 组件放在您的 parant react 组件中,它会显示您的网络摄像头源。对我来说就像一个魅力。

import React, {useEffect} from 'react'
const AppStreamCam = () => {
const streamCamVideo = () => {
var constraints = { audio: true, video: { width: 1280, height: 720 } };
navigator.mediaDevices
.getUserMedia(constraints)
.then(function(mediaStream) {
var video = document.querySelector("video");
video.srcObject = mediaStream;
video.onloadedmetadata = function(e) {
video.play();
};
})
.catch(function(err) {
console.log(err.name + ": " + err.message);
}); // always check for errors at the end.
}
useEffect(()=>{
streamCamVideo()
},[])
return (
<div>
<video autoPlay={true} id="videoElement" ></video>
</div>
);
}
export default AppStreamCam

您可以使用反应网络摄像头。 点击下面的链接,它已经有一个"getScreenshot"函数,可以从网络摄像头返回当前帧的base64编码图片。

https://www.npmjs.com/package/react-webcam

const WebcamCapture = () => {
const webcamRef = React.useRef(null);
const [imgSrc, setimgSrc] = React.useState(null);
const capture = React.useCallback(
() => {
const imageSrc = webcamRef.current.getScreenshot();
setimgSrc(imageSrc);
},
[webcamRef,setimgSrc]
);
return (
<div>
<Webcam
audio={false}
height={720}
ref={webcamRef}
screenshotFormat="image/jpeg"
width={1280}
/>
<button onClick={capture}>Capture photo</button>
{imgSrc && (<img src = {imgSrc}/>) }
</div>
);
};    

乐于帮忙!

最新更新