js 调用摄像头

通过 js 获取摄像头权限,进行录像预览,并可以进行下载。

启用摄像头

点击启用摄像头按钮后,调用navigator.mediaDevices.getUserMedia并将视频流绑定到<video>元素。

const startCamera = async () => {
  try {
    const stream = await navigator.mediaDevices.getUserMedia({
      video: true,
      audio: true,
    })

    if (videoRef.current) {
      videoRef.current.srcObject = stream
    }

    const recorder = new MediaRecorder(stream)
    recorder.ondataavailable = (event) => {
      if (event.data.size > 0) {
        setRecordedChunks((prevChunks) => [...prevChunks, event.data])
      }
    }

    recorder.onstop = () => {
      console.log('Recording stopped')
    }

    setMediaRecorder(recorder)
  } catch (error) {
    console.error('Failed to access camera:', error)
  }
}

开始录像

点击开始录像按钮调用MediaRecorder.start()开始录像。 点击停止录像按钮调用MediaRecorder.stop()停止录像。

const startRecording = () => {
  if (mediaRecorder) {
    mediaRecorder.start()
    setRecordedChunks([])
    setIsRecording(true)
  }
}
const stopRecording = () => {
  if (mediaRecorder) {
    mediaRecorder.stop()
    setIsRecording(false)
  }
}

保存录像

停止录像后,将 Blob 转换为可下载的链接。

const downloadRecording = () => {
  if (recordedChunks.length > 0) {
    const blob = new Blob(recordedChunks, { type: 'video/webm' })
    const url = URL.createObjectURL(blob)

    const a = document.createElement('a')
    a.href = url
    a.download = 'recording.webm'
    a.click()

    URL.revokeObjectURL(url)
  }
}

示例

相关代码

const JsCamera = () => {
  const videoRef = useRef<HTMLVideoElement>(null)
  const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder | null>(null)
  const [recordedChunks, setRecordedChunks] = useState<Blob[]>([])
  const [isRecording, setIsRecording] = useState(false)

  const startCamera = async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({
        video: true,
        audio: true,
      })

      if (videoRef.current) {
        videoRef.current.srcObject = stream
      }

      const recorder = new MediaRecorder(stream)
      recorder.ondataavailable = (event) => {
        if (event.data.size > 0) {
          setRecordedChunks((prevChunks) => [...prevChunks, event.data])
        }
      }

      recorder.onstop = () => {
        console.log('Recording stopped')
      }

      setMediaRecorder(recorder)
    } catch (error) {
      console.error('Failed to access camera:', error)
    }
  }

  const startRecording = () => {
    if (mediaRecorder) {
      mediaRecorder.start()
      setRecordedChunks([])
      setIsRecording(true)
    }
  }

  const stopRecording = () => {
    if (mediaRecorder) {
      mediaRecorder.stop()
      setIsRecording(false)
    }
  }

  const downloadRecording = () => {
    if (recordedChunks.length > 0) {
      const blob = new Blob(recordedChunks, { type: 'video/webm' })
      const url = URL.createObjectURL(blob)

      const a = document.createElement('a')
      a.href = url
      a.download = 'recording.webm'
      a.click()

      URL.revokeObjectURL(url)
    }
  }

  return (
    <Flex vertical={true} gap="large" align="center">
      <video
        ref={videoRef}
        autoPlay
        style={{ width: '80%', border: '1px solid black' }}
      ></video>
      <Flex gap="large" align="center">
        <Button
          type="primary"
          onClick={startCamera}
          disabled={mediaRecorder !== null}
        >
          启用摄像头
        </Button>
        <Button
          type="primary"
          onClick={startRecording}
          disabled={!mediaRecorder || isRecording}
        >
          开始录像
        </Button>
        <Button
          type="primary"
          onClick={stopRecording}
          disabled={!mediaRecorder || !isRecording}
        >
          停止录像
        </Button>
        <Button
          type="primary"
          onClick={downloadRecording}
          disabled={recordedChunks.length === 0}
        >
          下载录像
        </Button>
      </Flex>
    </Flex>
  )
}