我只是想构建一些类似实时录像机的东西(实际上不是),只是想每隔几秒在云端保存视频。
我在reactjs中编写了一些代码,当我的网络摄像头安装时,我启动摄像头并开始使用
mediaRecorder
进行录制,并希望在摄像头卸载时停止录制
我的代码:
import React, { useRef, useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { axiosServerInstance } from "@/utils/api/instances";
import { serverRoutes } from "@/utils/api/routes";
const cloudinaryUploadUrl = "https://api.cloudinary.com/v1_1/-----/video/upload";
const WebCam = () => {
const videoRef = useRef(null);
const mediaRecorderRef = useRef(null);
const recordedChunksRef = useRef([]);
const uploadIntervalRef = useRef(null);
const [isUploading,setIsUploading]=useState(false)
const isComponentMounted = useRef(true);
const proctorId = useSelector((state) => state?.assessment?.assessmentTestData?.report?.proctorId);
const updateProctorVideoUrl = async (chunks) => {
try {
await axiosServerInstance.put(serverRoutes.submitVideoUrl, {
proctorId,
...chunks,
});
} catch (error) {
console.error("Error updating proctor:", error.response?.data || error.message);
}
};
const uploadToCloudinary = async (blob) => {
if (!isComponentMounted.current) return;
const formData = new FormData();
formData.append("file", blob);
formData.append("upload_preset", "-----");
try {
const response = await fetch(cloudinaryUploadUrl, {
method: "POST",
body: formData,
});
const data = await response.json();
await updateProctorVideoUrl({
asset_id: data.asset_id,
public_id: data.public_id,
url: data.url,
proctorId,
});
} catch (error) {
console.error("Error uploading video:", error);
}
};
const startCamera = async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
if (videoRef.current) {
videoRef.current.srcObject = stream;
}
return stream;
} catch (error) {
console.error("Error accessing camera:", error);
throw error;
}
};
const startRecording = (stream) => {
recordedChunksRef.current = [];
const mediaRecorder = new MediaRecorder(stream, { mimeType: "video/mp4" });
mediaRecorder.ondataavailable = (event) => {
if (event.data.size > 0) {
recordedChunksRef.current.push(event.data);
}
};
mediaRecorder.onstop = async () => {
if (recordedChunksRef.current.length > 0 && !isUploading) {
setIsUploading(true);
const blob = new Blob(recordedChunksRef.current, { type: "video/mp4" });
await uploadToCloudinary(blob);
recordedChunksRef.current = [];
mediaRecorder.start();
setIsUploading(false);
}
};
mediaRecorder.start();
mediaRecorderRef.current = mediaRecorder;
uploadIntervalRef.current = setInterval(() => {
if (mediaRecorder.state === "recording" && !isUploading) {
mediaRecorder.stop();
}
}, 5000);
};
useEffect(() => {
let stream;
const init = async () => {
isComponentMounted.current = true;
stream = await startCamera();
startRecording(stream);
};
init();
return () => {
isComponentMounted.current = false;
if (uploadIntervalRef.current) {
clearInterval(uploadIntervalRef.current);
}
if (stream) {
stream.getTracks().forEach((track) => track.stop());
}
if (videoRef.current) {
videoRef.current.srcObject = null;
}
};
}, []);
return <video ref={videoRef} autoPlay muted className="w-full h-full object-cover" />;
};
export default WebCam;
我面临的问题
ps:如果有更便宜的实时录音机可以推荐一下
您的 uploadToCloudinary 函数可能会被多次调用,因为 setInterval 内的 mediaRecorder.stop() 调用会触发 mediaRecorder.onstop 事件,该事件又会开始新的录制并设置另一个间隔,可能会导致重叠调用。
1.确保单次上传触发
使用标志来确保上传过程(如果已经在进行中)不会再次启动。您已经在使用 isUploading,但让我们改进它的用法。
2.更仔细地管理录音和上传
为避免重叠调用,请确保正确管理录制和上传逻辑,并避免在 onstop 事件处理程序内立即重新启动录制(如果已经有正在进行的上传)。