0

我使用 ReactJS 来显示一个使用 HTML5 视频元素的实时流(来自我的网络摄像头)。OpenVidu 媒体服务器处理后端。我想使用该canvas元素使用 drawImage() 方法将视频直播流绘制到画布上。

我见过其他例子,但在它们中,视频元素总是有一个来源。我的没有来源 - 当我检查视频元素时,我看到的是: <video autoplay id="remote-video-zfrstyztfhbojsoc_CAMERA_ZCBRG"/>

这是我尝试过的,但是画布不起作用。

export default function Video({ streamManager }) {
  const videoRef = createRef()
  const canvasRef = createRef()

  useEffect(() => {
    if (streamManager && !!videoRef) {

      //OpenVidu media server attaches the live stream to the video element 
      streamManager.addVideoElement(videoRef.current)

      if (canvasRef.current) {
        let ctx = canvasRef.current.getContext('2d')
        ctx.drawImage(videoRef.current, 0, 0)
      }
    }
  })

  return (
    <>
      //video element displays the live stream 
      <video autoPlay={true} ref={videoRef} />

      // canvas element NOT working, nothing can be seen on screen 
      <canvas autoplay={true} ref={canvasRef} width="250" height="250" />
    </>
  )
}

更新:经过进一步调查,我意识到我需要使用 setInterval() 函数,因此提供了以下解决方案。

4

2 回答 2

1

canvas解决方案是在自包含组件中提取逻辑,并使用 asetInterval()以便它canvas每 100 毫秒(或根据需要)在 上绘制视频元素。

视频分量

import React, { useEffect, createRef } from 'react'
import Canvas from './Canvas'

export default function Video({ streamManager }) {
  const videoRef = createRef()

  useEffect(() => {
    if (streamManager && !!videoRef) {

      //OpenVidu media server attaches the live stream to the video element 
      streamManager.addVideoElement(videoRef.current)
    }
  })

  return (
    <>
      //video element displays the live stream 
      <video autoPlay={true} ref={videoRef} />

      //extract canvas logic in new component
      <Canvas videoRef={videoRef} />

    </>
  )
}

画布组件

import React, { createRef, useEffect } from 'react'

export default function Canvas({ videoRef }) {
  const canvasRef = createRef(null)

  useEffect(() => {
    if (canvasRef.current && videoRef.current) {
      const interval = setInterval(() => {
        const ctx = canvasRef.current.getContext('2d')
        ctx.drawImage(videoRef.current, 0, 0, 250, 188)
      }, 100)
      return () => clearInterval(interval)
    }
  })

  return (
    <canvas ref={canvasRef} width="250" height="188" />
  )
}
于 2020-01-23T20:31:46.150 回答
0

您正在使用不带参数的 useEffect,这意味着您的 useEffect 将在每次渲染中调用

  useEffect(() => {
     // every render 
  })

如果您只想在挂载时运行您的 drawImage,请使用 useEffect 和 []

  useEffect(() => {
      // run at component mount 
  },[])

或者,如果您想在任何参数更改时运行 drawImage,则将您的参数传递给它

   useEffect(() => {
          // run when your streamManager change
      },[streamManager])

根据您的要求使用它

于 2020-01-23T06:34:08.393 回答