【问题标题】:Live stream HTML5 video draw-to-canvas not working直播 HTML5 视频绘制到画布不工作
【发布时间】:2020-05-09 03:52:08
【问题描述】:

我使用 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() 函数,因此提供了以下解决方案。

【问题讨论】:

    标签: reactjs html5-canvas html5-video react-hooks openvidu


    【解决方案1】:

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

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

    如果你只想在挂载时运行你的 drawImage,那么使用 useEffect 和 []

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

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

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

    根据您的要求使用它

    【讨论】:

    • 感谢您的观察,useEffect 确实缺少参数 [],但这不是问题,因为在这种情况下,组件不会多次重新渲染自身。经过进一步调查,我发现我的组件中只需要一个 setInterval() 函数,因此我提供了以下解决方案。
    【解决方案2】:

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

    视频组件

    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" />
      )
    }
    

    【讨论】:

      猜你喜欢
      • 2016-02-23
      • 1970-01-01
      • 2012-08-22
      • 2011-09-26
      • 2014-02-07
      • 2014-12-03
      • 2014-10-12
      • 2015-03-26
      • 1970-01-01
      相关资源
      最近更新 更多