[英]ReactJS canvas drawImage without showing html5 video element
[英]HTML5 Canvas drawImage from video not showing on first draw
我有一个带有 canvas 叠加层的视频元素。 然后我有一个绘图工具设置来绘制视频和一个保存按钮,它从视频和 canvas 中执行 drawImage 以保存压缩帧。 但是,我第一次按“保存”时,我只从 canvas drawImage 获得结果,视频没有显示。 在随后的保存中,我收到了正确分层的两个图像。 我认为这可能是加载视频图像的问题,但在我点击保存之前视频已完全加载,甚至可以推进帧并使其在第二次保存时正常工作。
这是代码...
<div style="width:960px; height:540px; display:inline-block;">
<video id="video" src="media/_tmp/AA_017_COMP_v37.mov" width="960" height="540" ></video>
</div>
<canvas id="canvas" width="960" height="540" style="position:absolute; top:40px; left:9px; z-index:100;"></canvas>
<input type="button" value="save" id="btn" size="30" onclick="save()" style="float:left; padding:4px; margin-right:4px;" >
<div id="saved" style="border:1px solid #000; position:absolute; top:626px; left:10px; bottom:40px; width:958px; overflow:auto;">SAVED:</div>
function save() {
//COMP CANVAS OVER VIDEOFRAME
var video = document.getElementById("video");
var currentFrame = Math.floor((<?php echo $mov_frames ?> / video.duration) * video.currentTime);
var compCanvas = document.createElement('canvas');
compCanvas.width = video.width;
compCanvas.height = video.height;
compContext = compCanvas.getContext('2d');
compContext.drawImage(video, 0, 0);
compContext.drawImage(canvas, 0, 0);
var dataURL = compCanvas.toDataURL();
$("#saved").append('<div style="width:954px; border-bottom:1px solid #000; padding:2px 2px 0 2px;"><img id="compFrame_'+currentFrame+'" width="180" height="90" src="'+dataURL+'" />Frame: '+currentFrame+'</div>');
}
由于这是在带有Safari的OSX上,因此有一些坏消息:
注意:iOS当前不支持将视频作为canvas drawImage()方法的源。
如果这是过时的信息,我不知道,但是无论哪种情况,当前的实现都有问题。 正如已经确定的那样(在注释中),该问题不太可能与编解码器有关,因为其他格式也可能出现这种情况。 小提琴消除了toDataURL()
方法作为源,因此剩下的是drawImage()
方法。
由于这可以通过提供的代码在其他平台上使用,并且从外观上看,这也不是问题的根源,因此,您在这里查看的是OSX平台上Safari浏览器的一个非常可能的问题(错误)。
上面引用的官方文档还指出不支持此功能,因此这可能是一个非常早期的实现,仍然存在一些问题。
在这方面您无能为力,只能等待并报告为问题(我寻找了已报告的问题,但找不到任何问题,因此建议您这样做)。
最近,我本人也遇到了同样的问题,并通过将视频绘制到“虚拟”画布上来进行处理,然后再进行“实际”处理。 这与我代码中尝试解析视频的所有方法等到视频上触发了“ canplaythrough”事件一样,效果很好。 我将“ canplaythrough”事件处理程序包装在Promise中,并且仅在收到“ canplaythrough”事件并且试图将视频绘制到虚拟画布上时解决承诺。 这似乎是解决 Safari错误的有效方法 。
例如:
var readyPromise = new Promise(function(resolve) {
video.addEventListener("canplaythrough", function() {
var canvas = document.createElement("canvas"),
context = canvas.getContext("2d");
context.drawImage(video, 0, 0);
resolve(video);
});
});
readyPromise.then(function() {
// NOW manipulate the video, draw it onto a canvas, etc
});
我遇到了同样的问题,并在最后一条评论中尝试了解决方案。 它对我来说还行不通。
后来我想出了一个解决方法:
在我的代码中,我还有其他一些绘图以及视频中的drawImage
context.rect(0, 0, 50, 50);
context.fillStyle = 'black';
context.fill();
有了这些,即使在“ canplaythrough”事件后重新绘制,第二次绘制仍然不起作用。
因此,我删除了上述三行内容,只是在事件“ canplaythrough”之后进行了第二次抽签。 然后它起作用了。
简单来说,对我有用的代码是这样的:
context.drawImage(video, 0, 0);
video.addEventListener('canplaythrough', function () {
context.drawImage(video, 0, 0);
});
这些都不适合我。 似乎 chrome(atm 是97版)在后台做了一些讨厌的优化。
canplaythrough
似乎很懒惰,并且不保证第一帧已加载video
有 style display: none
它也不会被加载,因此绘图也不会工作。唯一有用的是setTimeout ,这是一个令人讨厌的 hack,但它就是这样。
fileinput.addEventListener('change', function (e) { var ctx = canvas.getContext("2d"); video.addEventListener('loadedmetadata', function () { canvas.width = video.videoWidth; canvas.height = video.videoHeight; setTimeout(() => { ctx.drawImage(video, 0, 0); }, 100) }); video.querySelector("source").setAttribute('src', URL.createObjectURL(fileinput.files[0])); video.load(); });
video { opacity: 0; width: 0; height: 0; }
<input type="file" id="fileinput" name="file"> <video id="video" controls> <source type="video/mp4"> </video> <canvas id="canvas"></canvas>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.