Javascript 移动safari在视频捕获过程中内存不足

Javascript 移动safari在视频捕获过程中内存不足,javascript,react-native,html5-canvas,webrtc,mobile-safari,Javascript,React Native,Html5 Canvas,Webrtc,Mobile Safari,我在课堂上讲了两个主要内容。画布和视频。 我得到视频流并以30fps的速度渲染到画布上 class GetImage extends Component { constructor() { super(); this.constraints = { video: { width: { ideal: 2048 }, height: { ideal: 1080 }, facingMode: { ex

我在课堂上讲了两个主要内容。画布和视频。 我得到视频流并以30fps的速度渲染到画布上

class GetImage extends Component {

  constructor() {
    super();
    this.constraints = {
      video: {
        width: { ideal: 2048 },
        height: { ideal: 1080 },
        facingMode: {
          exact: 'environment'
        }
      }
    }
  }

  componentDidMount() {
    setVideo(this.video, this.constraints, this.readyToPlayVideo)
  }

  capture = () => {
    const { video } = this
    let canvas = document.createElement('canvas')
    canvas.width = video.videoWidth
    canvas.height = video.videoHeight

    let context = canvas.getContext('2d')
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.drawImage(this.video, 0, 0, canvas.width, canvas.height)
    this.setState({ capture: canvas.toDataURL('image/jpeg') })
    stopVideo()
  }


  readyToPlayVideo = () => {
    const { canvas, video }  = this
    const { offsetHeight, offsetWidth } = video
    const ctx = canvas.getContext('2d')
    ctx.canvas.setAttribute('height', offsetHeight)
    ctx.canvas.setAttribute('width', offsetWidth)

    const timeout = 1000 / 30 // drawing at 30fps

    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

    let _listener = () => {
      (function loop() {
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
        ctx.drawImage(video, 0, 0)
        setTimeout(loop, timeout)
      })()
    }

    _listener();
  }


  retake = () =>
    this.setState({ capture: null },
      () => {
        setVideo(this.video, this.constraints, this.readyToPlayVideo, this.handleError)
      }
    )

  render() {
    return (
        <div>
          <video
            style={{ visibility: 'hidden'}}
            ref={video => (this.video = video)}
            playsInline
            autoPlay
          />
          <canvas ref={canvas => (this.canvas = canvas)}/>
        </div>
    )
  }
}
类GetImage扩展组件{ 构造函数(){ 超级(); 这是一个限制条件={ 视频:{ 宽度:{理想值:2048}, 高度:{理想值:1080}, 面向模式:{ 确切:“环境” } } } } componentDidMount(){ setVideo(this.video、this.constraints、this.readyToPlayVideo) } 捕获=()=>{ const{video}=this 让canvas=document.createElement('canvas') canvas.width=video.videoWidth canvas.height=video.videoHeight let context=canvas.getContext('2d') clearRect(0,0,canvas.width,canvas.height); context.drawImage(this.video、0、0、canvas.width、canvas.height) this.setState({capture:canvas.toDataURL('image/jpeg')}) 停止录像() } readyToPlayVideo=()=>{ const{canvas,video}=this const{offsetHeight,offsetWidth}=视频 const ctx=canvas.getContext('2d') ctx.canvas.setAttribute('height',offsetHeight) ctx.canvas.setAttribute('width',offsetWidth) 常数超时=1000/30//以每秒30帧的速度绘制 clearRect(0,0,ctx.canvas.width,ctx.canvas.height); 让_listener=()=>{ (函数循环(){ clearRect(0,0,ctx.canvas.width,ctx.canvas.height); ctx.drawImage(视频,0,0) setTimeout(循环,超时) })() } _监听器(); } 重拍=()=> this.setState({capture:null}, () => { setVideo(this.video,this.constraints,this.readyToPlayVideo,this.handleError) } ) render(){ 返回( (this.video=video)} playsInline 自动播放 /> (this.canvas=canvas)}/> ) } } 到目前为止还不错。 但我在移动Safari上遇到了一个问题。看起来它将所有创建的画布对象都保存在内存中

拍摄了几张照片后,Safari因“内存不足”而崩溃。
在渲染新图像之前,我已经执行了clearRect,但它没有帮助。

不确定这是否会100%解决您的问题,但是,这可能会有所帮助。不要对动画使用
setInterval
,而是使用
window.requestAnimationFrame

这里有一个例子

var requestAnimFrame = (function() {
    return  window.requestAnimationFrame       ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame    ||
            window.msRequestAnimationFrame     ||
            function( callback ) {
                window.setTimeout(callback, 1000 / 30);
            };
})();

function loop(){
     requestAnimFrame(loop);
     ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
     ctx.drawImage(video, 0, 0);
     setTimeout(loop, timeout);
}
loop();
再一次,我不是100%肯定这会解决你的问题,但是,它可能会有所帮助。如果你还有任何问题,请告诉我


我希望这有帮助

这里有几个问题需要解决。首先,您的
循环
函数中似乎有一个循环引用;您正在调用函数中的函数

因此,自动播放视频(渲染时)不会停止。。导致“内存不足”错误

另外,我认为最好的做法是创建一个
componentdidumount
函数来销毁视频(当不再需要时)。使用
.dispose
销毁视频


希望这能有所帮助

这是react Docshanks的一些样本。是的,循环引用看起来不太好。修正了。但我不知道如何真正销毁视频。React根据组件状态销毁视频标记,因此卸载组件节点不是解决方案。我不使用你链接中的videojs。我渲染视频或不渲染基于组件状态,看起来问题就在这里。每次我开始一个新视频时,我都会得到+20-100mb的内存使用量。@lasfin这里有一个。。它有点长,但给出了很好的例子。只需对代码进行一些调整。希望这有帮助。@lasfin如果您清除了componentDidUnmount上的超时,例如let(设置它)…,可能会有所帮助。。让yourvar=setTimeout(循环,超时);(然后在卸载中)。。。清除超时(yourvar);