Javascript 移动safari在视频捕获过程中内存不足
我在课堂上讲了两个主要内容。画布和视频。 我得到视频流并以30fps的速度渲染到画布上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
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);