【问题标题】:Is it normal for an HTMLCanvasElement captured stream to lag on Chrome when the Canvas is hidden and drawn onto by its OffscreenCanvas in a web worker当 Canvas 被 Web Worker 中的 OffscreenCanvas 隐藏并绘制到其上时,HTMLCanvasElement 捕获的流在 Chrome 上滞后是否正常?
【发布时间】:2021-11-07 06:36:54
【问题描述】:

好的,所以问题有点多,但它实际上提到了我遇到的“错误”的每个部分。我不确定这是否真的是一个错误,或者是否有一些我还不明白的东西。我在 codepen 上创建了一个演示来重现奇怪的行为。

https://codepen.io/rroyerrivard/pen/jOwBLbB

就像我在 codepen 中写的那样,Chrome 中似乎存在一个错误,HTMLCanvasElement 的流在隐藏时不会在每次绘制图像时都被刷新。但要做到这一点,需要同时具备这 4 个条件。

  • 我们必须通过调用HTMLCanvasElement.captureStream() 获得的MediaStream 提供HTMLVideoElement(而不是直接显示HTMLCanvasElement)。
  • 我们从中获得 MediaStreamHTMLCanvasElement 必须隐藏(不在 DOM 中或使用 css 隐藏)。
  • 我们必须利用来自OffscreenCanvasHTMLCanvasElement,我们从调用HTMLCanvasElement.transferControlToOffscreen() 得到。
  • OffscreenCanvas 的抽奖必须在将OffscreenCanvas 转移到的网络工作者中完成。

我很不幸,在工作中的网络应用程序中同时遇到了所有这些条件。我可以通过不使用 transferControlToOffscreen() 调用并在从 web worker 接收到 ImageBitmap 后在主线程中绘制一个 ImageBitmap 来避免该错误,但这会将 FPS 降低大约 18%。

这是一个已知的错误吗?有没有办法强制MediaStream 在每次绘制OffscreenCanvas 时刷新?

【问题讨论】:

    标签: javascript html5-canvas web-worker mediastream offscreen-canvas


    【解决方案1】:

    我猜这是预期的行为是的。

    这里的问题是您使用主线程中的 setTimeout 和 MessageEvents 让您的工作线程等待。
    OffscreenCanvas 会将其位图提交到 Worker 渲染帧中的占位符画布。但默认情况下,Worker 不会进入这个渲染帧。您需要使用 requestAnimationFrame 请求它。
    当占位符画布本身被渲染时(即在主线程的渲染框架中),让占位符在页面中可见将在内部请求 OffscreenCanvas 提交其位图,这就是当占位符画布可见时它起作用的原因。

    请注意,我们曾经有一个 OffscreenCanvas.commit() 方法,但当 requestAnimationFrame 在 WorkerContexts 中出现时,它已被弃用。

    因此,在您的 Worker 中使用 requestAnimationFrame 来实际强制将位图提交到占位符画布。

    const video = document.querySelector("video");
    const select = document.querySelector("select");
    const canvas = document.createElement("canvas");
    const offscreen = canvas.transferControlToOffscreen();
    const worker = new Worker(getWorkerURL());
    worker.postMessage({ offscreen }, [offscreen]);
    select.oninput = e => worker.postMessage({ method: select.value });
    worker.onmessage = (evt) => {
      video.srcObject = canvas.captureStream();
    };
    
    function getWorkerURL() {
      return URL.createObjectURL(
        new Blob([
          document.querySelector("[type='text/worker']").textContent
        ], { type: "text/javascript" })
      );
    }
    canvas { border: 1px solid }
    <video controls autoplay></video>
    <label>waiting method:<select><option>rAF</option><option>setTimeout</option></select></label>
    <script type="text/worker">
      let ctx;
      let waiting_method = "rAF";
      onmessage = ({ data: { offscreen, method } }) => {
        if (offscreen) {
          ctx = offscreen.getContext("2d");
          draw();
          postMessage("ready");
        }
        else if (method) {
          waiting_method = method;
        }
      };
      function draw() {
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
        ctx.fillText(new Date().getTime(), 30, 30);
        if (waiting_method === "rAF") {
          requestAnimationFrame(draw);
        }
        else {
          setTimeout(draw, 1000/30);
        }
      }
    </script>

    现在,我想我们还可以预期对 captureStream() 的调用实际上会触发与可见占位符画布触发的相同的内部提交请求,因此您可能需要在 https://crbug.com 提交问题。

    【讨论】:

    • 感谢您的建议@Kaiido。我尝试添加 requestAnimationFrame() 并修复了延迟,但我无法使用它,因为我的 Web 应用程序需要处理帧,即使关注不同的浏览器选项卡也是如此。
    • 实际上,调用requestAnimationFrame() 而不等待回调运行worker 代码修复了这个bug,并且当浏览器不同的选项卡被聚焦时不会冻结web worker。我仍然需要在不同的环境中测试,看看图像是否在选项卡未聚焦时以正确的速率刷新。测试后会发布更新。
    • 隐藏页面时,我的管道中的某些内容完全冻结了图像。我无法在我的 codepen 演示中直接对其进行测试,但在我的 Web 应用程序中,我将画布的捕获流发送给另一个用户(在我的情况下是在另一个选项卡中),这样我就可以看到图像冻结了。直接在 UI 线程的画布中绘制图像时,我没有遇到这个问题。因此,与 Web Worker 中屏幕外画布上的绘图相关的东西正在阻止流更新。
    • 那么 rAF 被限制用于背景文档,甚至是 Worker 的。如果您想要的是即使选项卡在后台也能继续绘制,那么不要使用 Worker,使用 WebAudio 计时器:stackoverflow.com/a/40691112/3702797
    • 我使用网络工作者的真正原因是因为在我的网络应用程序中进行了大量计算,然后再在屏幕外画布上绘图(调用神经网络进行分割)。既然我在绘制代码旁边打电圈(绘图代码不在RAF回调中),我的绘制代码仍然会在隐藏选项卡时调用。我已经用日志确定了这一点。但是,在隐藏选项卡时,画布的MediaStream无法更新。我不认为在这里使用音频计时器会有帮助。
    猜你喜欢
    • 2020-07-01
    • 1970-01-01
    • 2015-12-09
    • 2013-11-17
    • 1970-01-01
    • 2019-10-26
    • 1970-01-01
    • 1970-01-01
    • 2021-01-05
    相关资源
    最近更新 更多