HTML5视频到画布播放速度很慢

时间:2014-01-17 23:11:29

标签: javascript html5 video canvas

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

我使用以下教程来学习这个技巧https://www.youtube.com/watch?v=zjQzP3mOXdc

以下是相关代码,但可能存在来自其他地方的干扰,请随时查看底部链接的源代码

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;
  }
}

http://coreytegeler.com/ethan/

任何和所有帮助将不胜感激!谢谢!

3 个答案:

答案 0 :(得分:6)

原因1

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

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

34ms是充足的,因为视频帧速率通常不超过30 FPS(NTSC)或25 FPS(PAL),即1000 / 30。如果您使用0,则存在堆叠呼叫的风险,这意味着浏览器将忙于尝试清空事件队列。

如果您使用低于33-34ms的任何内容,您最终会将相同的帧处理两次或更多次,这当然是不必要的(您的视频实际上是29.97 FPS / NTSC,因此您可能需要考虑保留34ms)。

原因2

视频分辨率也是全高清(1920x1080),对于画布和JS来说实时处理(对于典型的消费者电脑)来说有点太多了。尝试减小视频大小,以便正常规格的计算机能够处理数据。

原因3(部分)

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

原因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中提到这一点。您可以简单地使用单个屏幕画布和屏幕外视频,并将视频帧绘制到画布,处理它并放回处理过的数据。在这种情况下也应该正常工作。

答案 1 :(得分:1)

我在chrome中运行了一个配置文件,它指向第46行占用了最多的CPU。

enter image description here

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

或许增加超时会使其停止滞后。

答案 2 :(得分:0)

我遇到了相同的问题,并尝试了许多修复程序。我使用的是不会导出到mp4的Premier Elements,并使用了HandBrake来转换​​格式。我还尝试了FFMpeg进行转换,但均无济于事。

我所做的就是切换到Kdenlive作为我的视频编辑器,将其直接导出到MP4,并且该视频运行完美。

因此,如果您遇到此缓慢的渲染问题,则可能是视频编码存在问题。最简单的解决方法是获得高质量的视频编辑器,例如Premier Pro,Final Cut或Kdenlive。 Kdenlive是免费的,但学习曲线很大,公开文档也很差。