我正在创建一个 React 应用程序,用于对候选人进行网络摄像头面试。候选人还可以“重新开始”或“完成”他们的面试。
为了显示录制的数据,我尝试将其显示为 HTML 视频。但是,我遇到了录制后视频不出现的问题。视频数据当前为 blob 格式。
此外,我还添加了一个下载按钮;当用户下载视频时,它可以正常工作并保存在本地。
我尝试了一些解决方案来解决显示问题。我尝试在 src 属性中使用 .mp4 或 .webm 扩展名直接嵌入视频。我还尝试过第三方 React 视频播放器 npm 包。不幸的是,到目前为止,这些方法都没有成功。
import Webcam from 'react-webcam';
const Index = (props) => {
const [timer, setTimer] = useState(0);
const [totalTime, setTotalTime] = useState(0);
const [video, setVideo] = useState(null);
const [isRecording, setIsRecording] = useState(false);
const [isVideoComplete, setIsVideoComplete] = useState(false);
const [webcamLoading, setWebcamLoading] = useState(true);
const webcamRef = useRef(null);
const mediaRecorderRef = useRef(null);
const timeIntervalRef = useRef(null);
const [recordedChunks, setRecordedChunks] = useState([]);
const maxRecordingTime = 180;
const videoConstraints = {
aspectRatio: 0.6666666667,
width: 1280,
height: 720,
facingMode: 'user',
};
const audioConstraints = {
suppressLocalAudioPlayback: true,
noiseSuppression: true,
echoCancellation: true,
};
const stopTimer = () => {
clearInterval(timeIntervalRef.current);
};
const formatTime = (seconds) => {
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
return `${minutes}:${remainingSeconds < 10 ? '0' : ''}${remainingSeconds}`;
};
const handleDataAvailable = React.useCallback(
({ data }) => {
if (data.size > 0) {
setRecordedChunks((prev) => prev.concat(data));
}
},
[setRecordedChunks]
);
// Stop Recording
const handleStopRecording = useCallback(() => {
setIsVideoComplete(true);
setShowStats(true);
stopTimer();
console.log(isRecording, mediaRecorderRef.current);
if (isRecording && mediaRecorderRef.current) {
setIsRecording(false);
const blob = new Blob(recordedChunks, { type: 'video/webm' });
// Blob { size: 0, type: 'video/webm' }
console.log(blob);
setVideo(blob);
mediaRecorderRef.current.stop();
}
}, [isRecording, recordedChunks]);
const startTimer = useCallback(() => {
setTimer(0);
timeIntervalRef.current = setInterval(() => {
setTimer((prevTimer) => {
if (prevTimer >= maxRecordingTime) {
handleStopRecording();
return prevTimer;
}
return prevTimer + 1;
});
}, 1000);
}, [handleStopRecording]);
// Start Recording
const handleStartRecording = useCallback(() => {
setShowStats(false);
setIsVideoComplete(false);
if (!isRecording) {
setIsRecording(true);
startTimer();
if (webcamRef.current && webcamRef.current.video.srcObject) {
const stream = webcamRef.current.video.srcObject;
mediaRecorderRef.current = new MediaRecorder(stream, {
mimeType: 'video/webm',
});
mediaRecorderRef.current.addEventListener('dataavailable', handleDataAvailable);
mediaRecorderRef.current.start();
}
}
}, [handleDataAvailable, isRecording, startTimer]);
const handleCompleteRecording = () => {
setShowStats(true);
if (video) {
sendVideo(video);
}
};
// Download Video
const handleDownload = React.useCallback(() => {
if (recordedChunks.length) {
const blob = new Blob(recordedChunks, {
type: 'video/webm',
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
document.body.appendChild(a);
a.style = 'display: none';
a.href = url;
a.download = 'react-webcam-stream-capture.webm';
a.click();
window.URL.revokeObjectURL(url);
setRecordedChunks([]);
}
}, [recordedChunks]);
const handleStartAgain = () => {
setIsRecording(false);
setShowStats(false);
setIsVideoComplete(false);
setVideo(null);
stopTimer();
setTimer(0);
};
const sendVideo = (video) => {
const formData = new FormData();
formData.append('video', video, 'interview.webm');
console.log('Posting Video...', video);
};
return (
<div className={classes.mainContent}>
<>
<Grid container>
<Grid item xs={8} className={classes.rightSection}>
<Grid container>
{/* Record Section */}
<Grid item xs={12} md={12} className={classes.recordingScreen}>
<div style={{ height: '480px', width: '100%', position: 'relative' }}>
{/* {webcam && ( */}
{!video ? (
webcamLoading ? (
<CircularProgress style={{ height: '2.5rem', width: '2.5rem' }} color="inherit" />
) : (
<div className={`webcamContainer ${webcamLoading ? 'webccamLoading' : ''}`}>
<Webcam
ref={webcamRef}
audio={true}
mirrored={true}
muted={true}
onUserMedia={handleUserMedia}
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
videoConstraints={videoConstraints}
audioConstraints={audioConstraints}
/>
</div>
)
) : (
<>
{video && (
<>
<video
src={video ? URL.createObjectURL(video) : ''}
controls
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
onError={(e) => {
console.log('Error', e);
}}
/>
{recordedChunks.length > 0 && <button onClick={handleDownload}>Download</button>}
</>
)}
</>
)}
</div>
</Grid>
});
export default withStyles(materialStyles)(Index);
注意:我不使用 React,所以请尝试修复以下错误:
解决方案是将视频标签的源替换为您的 blob。
您可以尝试的起点(关于上述概念)...
(1)。使用它作为您的
<video>
标签设置(例如: 您必须为此元素设置 ref):
<video
ref={videoRef}
type="video/mp4"
src=""
controls
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
onError={(e) => { console.log('Error', e); }}
/>
(2) 然后使用
\\Download Video
函数来播放 blob(因为你说它有有效数据):
//# Download Video
const handleDownload = React.useCallback(() => {
if (recordedChunks.length)
{
const blob = new Blob(recordedChunks, { type: 'video/webm' });
const url = URL.createObjectURL(blob);
//# test playback ...
videoRef.current.src = url;
videoRef.current.load();
videoRef.current.play();
//# save as file
const a = document.createElement('a');
document.body.appendChild(a);
a.style = 'display: none';
a.href = url;
a.download = 'react-webcam-stream-capture.webm';
a.click();
window.URL.revokeObjectURL(url);
setRecordedChunks([]);
}
}, [recordedChunks] );
PS: 另一件需要注意的事情是,在 Apple 硬件上,您可能会以
video/mp4
类型而不是 video/webm
类型获取视频。我知道 iOS 上的 Safari 浏览器会创建 MP4 视频。只是说,如果 HTML 标记仍然不起作用,请考虑您的操作系统和/或浏览器是否影响结果。 video/webm
而无法工作?