首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >反应:在特定的框架上渲染画布

反应:在特定的框架上渲染画布
EN

Stack Overflow用户
提问于 2018-01-05 19:51:25
回答 1查看 1.6K关注 0票数 2

很新的反应,试着理解它的基本原理。我想在画布播放时将视频内容渲染到画布上。我的解决方案会导致溢出。如何管理这样的递归调用?

代码语言:javascript
复制
import React, {Component} from 'react';


class VideoPlayer extends React.Component {

    componentDidMount() {
        this.context = this.refs.canvas.getContext('2d');
    }

    play() {
        if (this.refs.video.paused) {
            this.refs.video.play();
            this.updateCanvas();
        } else {
            this.refs.video.pause();
        }
    }

    updateCanvas() {
        if (this.refs.video.paused || this.refs.video.ended) {
            return;
        }

        let fps = 30;
        this.context.drawImage(this.refs.video, 0, 0, 400, 220);

        setTimeout(requestAnimationFrame(this.updateCanvas()), 1000 / fps);
    }

    render() {
        return (
            <div>
                <video width="400" ref="video" id="v">
                    <source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4"/>
                </video>
                <canvas ref="canvas" width="400" height="220"></canvas>
                <br/>
                <button type="button" onClick={this.play.bind(this)}>Play</button>
            </div>

        );
    }
}

export default VideoPlayer;
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-01-05 23:34:49

如果您想定期打电话,最好使用setIntervalclearInterval,而不是setTimeout。递归总是有点棘手,处理延迟会使整个方法更加棘手。

因此,当play被按下(视频还没有播放)时,这个想法变成了编程一个setInterval,它会将当前的视频帧复制到画布中,并以n fps的速度完成。返回的interval处理程序将保存到组件的状态。

当play再次按下(视频正在运行)时,将通过调用保存在状态中的clearInterval值来清除interval函数。

此外,为了处理允许视频运行的情况,如果当我们按play (而且视频尚未运行)时,interval处理程序被设置在状态中,那么我们只需使用状态中的interval处理程序调用clearInterval (如果不这样做,每次视频运行到其末端=内存泄漏时,都会有未清除的间隔堆积)。

为了获得当前视频帧的副本,我们还实现了一个非常基本的grabFrame方法,并确保它绑定到组件的上下文中。

最后,我们获取副本(即FPS)的速率作为支柱传递给组件。

代码语言:javascript
复制
class VideoPlayer extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      interval: undefined,
      ctx: undefined
    };

    this.grabFrame = this.grabFrame.bind(this);
  }

  componentDidMount() {
    this.setState({
      ctx: this.canvas.getContext("2d")
    });
  }

  grabFrame() {
    return this.state.ctx.drawImage(this.video, 0, 0, 400, 220);
  }

  play() {
    if (this.video.paused) {
      if (this.state.interval) {
        clearInterval(this.state.interval);
      }
      this.video.play();
      this.setState({
        interval: setInterval(this.grabFrame, 1000 / this.props.fps)
      });
    } else {
      clearInterval(this.state.interval);
      this.setState({
        interval: undefined
      });
      this.video.pause();
    }
  }

  render() {
    return (
      <div>
        <video width="400" ref={video => (this.video = video)} id="v">
          <source
            src="https://www.w3schools.com/html/mov_bbb.mp4"
            type="video/mp4"
          />
        </video>
        <canvas
          ref={canvas => (this.canvas = canvas)}
          width="400"
          height="220"
        />
        <br />
        <button type="button" onClick={this.play.bind(this)}>
          Play
        </button>
      </div>
    );
  }
}

有关工作示例,请参见这个CodeSandbox

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48120376

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档