1

我有一个视频将像素复制到画布上,并使用网络工作者应用实时位图过滤器。

使用网络工作者时,我在画布上看不到由此产生的变化(应该是黑色和白色)。

这是我的代码: http: //www.dev.createdbychristian.com/filter-test/

我可以通过使用中间画布来解决这个问题,但我真的不想这样做。

我的代码大致基于此示例,与我的代码相同,只是没有使用网络工作者进行图像过滤处理。 http://techslides.com/demos/html5-video-canvas.html

我的代码有什么问题?

注意:需要支持 Web Workers 和 HTML5 Video / canvas 的现代浏览器

4

1 回答 1

6

发生这种情况是因为draw()不等待 WebWorker 的返回值并使用requestAnimationFrame. 如果您想要连续过滤图像,则必须draw在应用过滤器后调用:

filterWorker.addEventListener('message', function(e) {
    ctx.putImageData(e.data, 0, 0);
    requestAnimationFrame(draw);
}, false);

但是,如果过滤器需要很长时间,很可能draw会在早期用彩色数据填充画布以注意到变化(我能够在当前版本中看到带有 FF17 的黑白版本)。

我的代码有什么问题?

在操作顺序很重要的场景中,您正在使用一种用于并行计算的工具:您希望在显示之前对每个图像应用过滤器。让我引用 MDN

关于线程安全

Worker接口产生了真正的操作系统级线程,细心的程序员可能会担心,如果您不小心,并发可能会在您的代码中产生“有趣”的效果。

但是,由于 web Worker 已经仔细控制了与其他线程的通信点,因此实际上很难引起并发问题。无法访问非线程安全组件或 DOM。而且您必须通过序列化对象将特定数据传入和传出线程。所以你必须非常努力地在你的代码中引起问题。

与真正的操作系统级线程一样,除非您使用某种阻塞机制,否则无法对执行顺序做出任何假设,但这不包含在 JavaScript 中。所以你需要在同一个线程中绘制和操作图像。

进一步说明

顺序案例

看看下面的图片:

顺序过滤

这就是技术演示中基本上发生的事情。draw()复制视频并立即过滤图像:

function draw(v,c,w,h,filter) {
    if(v.paused || v.ended) return false;
    c.drawImage(v,0,0,w,h);
    if (typeof filter === 'undefined') {
        // variable is undefined
    } else {
        var idata = c.getImageData(0,0,w,h);
        newdata = filterdata(idata,filter);
        c.putImageData(newdata,0,0);
    }
    setTimeout(draw,20,v,c,w,h,filter);
}

如您所见,drawImage以下过滤器的调用之间没有间隙。生成的图片显示大约 20 毫秒。即使过滤器需要 1 毫秒,用户也可能不会注意到这一点。

平行案例

现在它变得有点复杂了。黑化文本框是直接修改画布的方法,白框表示触发事件或注册超时,黑框表示超时执行或事件处理:

平行案例

现在,会发生什么?draw仍然大约每 20 毫秒调用一次并复制视频。然后它向工人发布一条消息。但是,没有说明何时发送此消息。它可以立即放在worker的事件循环中(如图所示),也可以放在“main”的事件循环中并稍后调度(这种可能性更大)。

与顺序方法相比,此过程需要非常非常长的时间。请记住,您还需要将处理后的数据发回,并且filterfilterWorker的事件侦听器可能会在比您最初预期的时间更晚的时间触发。但即使你真的处理数据并显示它,下面的调用draw也会毁掉你所有的辛勤工作。

解决方案

要么不使用网络工作者,要么使用隐藏的画布作为工作者的来源。

于 2012-11-30T09:23:41.130 回答