标签处于非活动状态/用于录制时为背景时,画布不会重新绘制(WebGL) [英] Canvas doesn't repaint when tab inactive/ backgrounded for recording ( WebGL)

查看:46
本文介绍了标签处于非活动状态/用于录制时为背景时,画布不会重新绘制(WebGL)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建在线Web应用程序,该应用程序在画布上呈现视频,然后使用canvas.captureStream()和mediaRecorder记录画布。问题在于,当用户切换选项卡或最小化窗口时,画布会冻结。我使用了webWorkerSetInterval(Hacktimer.js)后,动画一直保持运行状态。根据chrome,他们尚未提供解决方案 https://bugs.chromium .org / p / chromium / issues / detail?id = 639105

I am building online web application which renders a video on a canvas and then records the canvas using canvas.captureStream() and mediaRecorder. The problem is that when the user switches tab or minimizes the window the canvas freezes. My animation keeps running as I have used webWorkerSetInterval(Hacktimer.js). As per chrome they have not yet provided a solution https://bugs.chromium.org/p/chromium/issues/detail?id=639105.

有人可以建议解决方法吗?我尝试了新窗口,该窗口不允许最小化,但是没有成功。切换窗口时录音不会停止。(仅在切换或最小化选项卡时停止)

Can anyone suggest a work-around? I tried new window which doesn't allow to minimize but was unsuccessful. The recording doesn't stop when switching window.(stops only when tab is switched or minimized)

推荐答案




NB:

现在,已经对该问题进行了专门编辑以处理webgl上下文,它可能并不完全是此先前的答案,这确实不适用于webgl上下文;但是由于存在chrome错误...


NB:
Now that this question has been specifically edited to treat webgl contexts, it may not be completely a duplicate of this previous answer, which indeed doesn't work with webgl contexts ; but because of an chrome bug...

因此,此答案将向您展示如何在等待chrome修复之前解决该错误。

So this answer will show you how to workaround this bug, while waiting for a fix from chrome.

链接的答案利用WebAudio API的计时方法创建了一个Timed循环,与屏幕刷新率和窗口/选项卡无关能见度。

The linked answer made use of the WebAudio API's timing method to create an Timed loop, not tied to the screen refresh-rate nor the window / tab's visibility.

但是正如标题中所述,当前不适用于chrome上的webgl上下文。

But as said in the header, this currently doesn't work with webgl contexts on chrome.

一种简单的解决方法是使用屏幕外的2d上下文作为流源,并将我们的webgl画布绘制到此2d上下文上:

The easy workaround, is to use an offscreen 2d context as the stream source, and to draw our webgl canvas onto this 2d context :

function startRecording(webgl_renderer, render_func) {
  // create a clone of the webgl canvas
  var canvas = webgl_renderer.domElement.cloneNode();
  // init an 2D context
  var ctx = canvas.getContext('2d');
  function anim(){
    // render the webgl Animation
    render_func();
    // draw the wegbl canvas on our 2D one
    ctx.clearRect(0,0,canvas.width, canvas.height);
  	ctx.drawImage(webgl_renderer.domElement, 0,0);
  }
	var fps = 60;
  // start our loop @60fps
  var stopAnim = audioTimerLoop(anim, 1000 / fps);
  // maximum stream rate set as 60 fps
  var cStream = canvas.captureStream(fps);

  let chunks = [];
  var recorder = new MediaRecorder(cStream);
  recorder.ondataavailable = e => chunks.push(e.data);
  recorder.onstop = e => {
    // we can stop our loop
    stopAnim();
    var url = URL.createObjectURL(new Blob(chunks));
    var v = document.createElement('video');
    v.src = url;
    v.controls = true;
    document.body.appendChild(v);
  }
  recorder.start();
  // stops the recorder in 20s, try to change tab during this time
  setTimeout(function() {
    recorder.stop();
  }, 20000);
  btn.parentNode.removeChild(btn);
}


/*
    An alternative timing loop, based on AudioContext's clock

    @arg callback : a callback function 
        with the audioContext's currentTime passed as unique argument
    @arg frequency : float in ms;
    @returns : a stop function

*/
function audioTimerLoop(callback, frequency) {

  var freq = frequency / 1000;      // AudioContext time parameters are in seconds
  var aCtx = new AudioContext();
  // Chrome needs our oscillator node to be attached to the destination
  // So we create a silent Gain Node
  var silence = aCtx.createGain();
  silence.gain.value = 0;
  silence.connect(aCtx.destination);

  onOSCend();

  var stopped = false;       // A flag to know when we'll stop the loop
  function onOSCend() {
    var osc = aCtx.createOscillator();
    osc.onended = onOSCend; // so we can loop
    osc.connect(silence);
    osc.start(0); // start it now
    osc.stop(aCtx.currentTime + freq); // stop it next frame
    callback(aCtx.currentTime); // one frame is done
    if (stopped) {  // user broke the loop
      osc.onended = function() {
        aCtx.close(); // clear the audioContext
        return;
      };
    }
  };
  // return a function to stop our loop
  return function() {
    stopped = true;
  };
}

/* global THREE */
/* Note that all rAF loop have been removed
   since they're now handled by our 'audioTimerLoop' */


(function() {

    'use strict';
    var WIDTH = 500, HEIGHT = 500;
    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(75, WIDTH / HEIGHT, 0.1, 1000);

    var renderer = new THREE.WebGLRenderer();
    renderer.setSize(WIDTH , HEIGHT);
    document.body.appendChild(renderer.domElement);

    var geometry = new THREE.CubeGeometry(5, 5, 5);
    var material = new THREE.MeshLambertMaterial({
        color: 0x00fff0
    });
    var cube = new THREE.Mesh(geometry, material);
    scene.add(cube);

    camera.position.z = 12;
    
    var pointLight = new THREE.PointLight(0xFFFFFF);

    pointLight.position.x = 10;
    pointLight.position.y = 50;
    pointLight.position.z = 130;

    scene.add(pointLight);

    var render = function() {        
        var delta = Math.random() * (0.06 - 0.02) + 0.02;

        cube.rotation.x += delta;
        cube.rotation.y += delta;
        cube.rotation.z -= delta;

        renderer.render(scene, camera);
    };
    render();
    console.clear();
    
    btn.onclick = function(){startRecording(renderer, render);};

}());

body {
    margin: 0;
    background: #000;
}
button{
  position: absolute;
  top: 0;
  }

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/85/three.min.js"></script>
<!-- Mobile devices need an user interaction to start the WebAudio API -->
<button id="btn">Start</button>

这篇关于标签处于非活动状态/用于录制时为背景时,画布不会重新绘制(WebGL)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆