Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/427.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript HTML5视频到画布播放速度非常慢_Javascript_Html_Video_Canvas - Fatal编程技术网

Javascript HTML5视频到画布播放速度非常慢

Javascript HTML5视频到画布播放速度非常慢,javascript,html,video,canvas,Javascript,Html,Video,Canvas,我已经构建了这个HTML5视频播放器,我正在将它加载到画布中进行操作,然后返回到画布上进行显示。视频开始时非常慢,每次播放时帧速率只会变得更差。我现在在视频中操作的只是暂停视频时的颜色值,但最终将在将来发布的整个视频中使用实时操作 我使用下面的教程来学习这个技巧 这里是相关的代码,但可能有来自其他地方的干扰,所以请随时检查底部链接的源代码 var v = document.getElementById('video'); var color = "#DA7AC1"; var processes=

我已经构建了这个HTML5视频播放器,我正在将它加载到画布中进行操作,然后返回到画布上进行显示。视频开始时非常慢,每次播放时帧速率只会变得更差。我现在在视频中操作的只是暂停视频时的颜色值,但最终将在将来发布的整个视频中使用实时操作

我使用下面的教程来学习这个技巧

这里是相关的代码,但可能有来自其他地方的干扰,所以请随时检查底部链接的源代码

var v = document.getElementById('video');
var color = "#DA7AC1";
var processes={
  timerCallback:function() {
    if (this.v2.paused || this.v2.ended) {
      return;
    }
        this.ctxIn.drawImage(this.v2,0,0,this.width,this.height);
        this.pixelScan();
        var self=this;
        setTimeout(function() {
          self.timerCallback();
        }, 0);
  },
  doLoad:function(){
    this.v2=document.getElementById("video");
    this.cIn=document.getElementById("cIn");
    this.ctxIn=this.cIn.getContext("2d");
    this.cOut=document.getElementById("cOut");
    this.ctxOut=this.cOut.getContext("2d");
    var self=this;
    this.v2.addEventListener("playing", function() {
      self.width=self.v2.videoWidth;
      self.height=self.v2.videoHeight;
      cIn.width=self.v2.videoWidth;
      cIn.height=self.v2.videoHeight;
      cOut.width=self.v2.videoWidth;
      cOut.height=self.v2.videoHeight;
      self.timerCallback();
    }, false);
  },
  pixelScan: function() {
    var frame = this.ctxIn.getImageData(0,0,this.width,this.height);
    for(var i=0; i<frame.data.length;i+=4) {
      var grayscale=frame.data[i]*.3+frame.data[i+1]*.59+frame.data[i+2]*.11;
      frame.data[i]=grayscale;
      frame.data[i+1]=grayscale;
      frame.data[i+2]=grayscale;
    }
    this.ctxOut.putImageData(frame,0,0);
    return;
  }
}
var v=document.getElementById('video'); var color=“#DA7AC1”; var过程={ timerCallback:函数(){ 如果(this.v2.paused | | this.v2.end){ 返回; } this.ctxIn.drawImage(this.v2,0,0,this.width,this.height); 这是pixelScan(); var self=这个; setTimeout(函数(){ self.timerCallback(); }, 0); }, doLoad:function(){ this.v2=document.getElementById(“视频”); this.cIn=document.getElementById(“cIn”); this.ctxIn=this.cIn.getContext(“2d”); this.cOut=document.getElementById(“cOut”); this.ctxOut=this.cOut.getContext(“2d”); var self=这个; 这个.v2.addEventListener(“播放”,函数(){ self.width=self.v2.videoWidth; self.height=self.v2.videoHeight; cIn.width=self.v2.videoWidth; cIn.height=self.v2.videoHeight; cOut.width=self.v2.videoWidth; cOut.height=self.v2.videoHeight; self.timerCallback(); },假); }, 像素扫描:函数(){ var frame=this.ctxIn.getImageData(0,0,this.width,this.height);
对于(var i=0;i我在chrome中运行了一个配置文件,它指出第46行占用了最多的CPU

setTimeout(function() {
    self.timerCallback();
}, 0);

增加超时时间可能会阻止其延迟。

原因1 尝试调整计时器,避免将0作为超时值:

setTimeout(function() {
      self.timerCallback();
}, 34);
34ms是足够的,因为视频帧速率通常不超过30 FPS(NTSC)或25 FPS(PAL),即
1000/30
。如果使用0,则可能会堆积呼叫,这意味着浏览器将忙于清空事件队列

如果你使用低于33-34毫秒的任何一个,你最终会得到相同的帧处理两次或更多,当然这是不必要的(你的视频实际上是29.97 FPS/NTSC,所以你可能需要考虑保持34毫秒)。 理由2 视频分辨率也是全高清(1920x1080),对于canvas和JS来说实时处理(对于典型的消费类计算机)有点太高了。尽量减小视频大小,以便普通规格的计算机能够处理数据

理由3(部分) 您不需要两个屏幕上的画布,甚至不需要一个屏幕上的视频。请尝试动态创建这些标记,而不要将它们插入DOM。在屏幕上使用单个画布并将结果绘制到该画布上(您可以将ImageData从一个画布放到另一个画布上)

理由4(部分) 理想情况下,将
setTimeout
替换为
requestAnimationFrame
方法,因为这大大提高了同步性和效率。您可以实现切换,将FPS降低到例如30,因为您不需要对每个帧进行两次处理(参考30 FPS视频帧速率)

更新

要动态创建这些元素(参考原因3),可以执行以下操作:

var canvas = document.createElement('canvas'),
    video = document.createElement('video'),
    ctx = canvas.getContext('2d');

video.preload = 'auto';
video.addEventListener('canplay', start, false);

if (video.canPlayType('video/mp4')) {
    video.src = 'videoUrl.mp4';

} else if ...etc.
然后,当视频加载了足够的数据(在元数据或canplay上)时,将屏幕外(和屏幕上)画布元素设置为视频的大小:

canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
然后在播放时处理其缓冲区并复制到您之前定义的屏幕画布


你没有屏幕外的画布-我只是在你使用的原始代码和输入输出画布IIRC中提到这一点。你可以简单地使用一个屏幕上的画布和屏幕外的视频,并将视频帧绘制到画布上,处理它并放回处理过的数据。在这种情况下也应该可以正常工作。

我也有同样的问题并尝试了一些修复。我使用了未导出到mp4的Premier元素,并使用HandBrake转换格式。我还尝试了FFMpeg进行转换,但都不起作用

我所做的是切换到Kdenlive作为我的视频编辑器,它直接导出到MP4,视频工作得非常好


因此,如果您遇到渲染速度慢的问题,这可能是视频编码的问题。最简单的解决方法是获得一个高质量的视频编辑器,如Premier Pro、Final Cut或Kdenlive。Kdenlive是免费的,但它有一个巨大的学习曲线和糟糕的公共文档。

哇,谢谢您,修复了超时值,并且已经注意到了在初始加载时播放速度更快。但是在播放了一两次之后,它仍然会变得完全混乱。我将继续按照您的建议进行操作,我不知道我能够在不将额外的画布和视频标签放到页面上的情况下实现我的预期目标。这应该会清除一切!我不是苏re如果我知道如何动态添加画布和视频标签,以及如何添加所有相同的参数和源。如果我删除了下面的代码,所有内容似乎都被清除了,我仍然计划采取进一步的措施以确保快速缓冲,但目前唯一的问题是,暂停时它会返回几帧,猜测这可能是f与
requestAnimationFrame
----
var self=this;setTimeout(function(){self.timerCallback();},0);
@CoreyTegeler我更新了我的答案,提供了一些关于如何动态创建视频/画布元素的详细信息。是的!将其更改为34肯定会消除一些延迟