canvas html5-canvas mediastream web-mediarecorder

CanvasCaptureMediaStream/MediaRecorder Sincronización de cuadros



html5-canvas web-mediarecorder (1)

Este ejemplo actualmente solo funciona completamente en FireFox , ya que Chrome simplemente detiene la transmisión del lienzo cuando la pestaña está borrosa ... (probablemente relacionado con este error , pero bueno, mi temporizador parece estar funcionando pero no la grabación ...)

[Editar] : en realidad ahora solo funciona en Chrome, ya que han solucionado este error , pero ya no en FF debido a este (causado por e10s).

No parece haber ningún evento en MediaStream que le permita saber cuándo se ha procesado un marco, ni en el MediaRecorder.

Incluso la propiedad currentTime de MediaStream (actualmente solo disponible en FF) no parece estar cambiando en consecuencia con el argumento fps pasado en el método captureStream() .

Pero lo que parece querer es un temporizador confiable, que no pierda su frecuencia cuando, por ejemplo, la pestaña actual no esté enfocada (lo que sucede para rAF).
Afortunadamente, la API de WebAudio también tiene un temporizador de alta precisión , basado en el reloj de hardware, en lugar de en la frecuencia de actualización de la pantalla.

Por lo tanto, podemos venir con un ciclo temporizado alternativo, capaz de mantener su frecuencia incluso cuando la pestaña está borrosa.

/* 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) { // AudioContext time parameters are in seconds var freq = frequency / 1000; 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; function onOSCend() { osc = aCtx.createOscillator(); osc.onended = onOSCend; osc.connect(silence); osc.start(0); osc.stop(aCtx.currentTime + freq); callback(aCtx.currentTime); if (stopped) { osc.onended = function() { return; }; } }; // return a function to stop our loop return function() { stopped = true; }; } function start() { // start our loop @25fps var stopAnim = audioTimerLoop(anim, 1000 / 25); // maximum stream rate set as 25 fps cStream = canvas.captureStream(25); 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) } // make something move on the canvas var ctx = canvas.getContext(''2d''); var x = 0; function anim() { x = (x + 2) % (canvas.width + 100); ctx.fillStyle = ''ivory''; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = ''red''; ctx.fillRect(x - 50, 20, 50, 50) }; start();

<canvas id="canvas" width="500" height="200"></canvas>

Nota Bene :
En este ejemplo, configuré la frecuencia a 25 fps, pero podemos configurarla a 60 fps y parece funcionar correctamente incluso en mi vieja computadora portátil, al menos con una animación tan simple.

Al usar CanvasCaptureMediaStream y MediaRecorder, ¿hay alguna forma de obtener un evento en cada fotograma?

Lo que necesito no es diferente a requestAnimationFrame() , pero lo necesito para CanvasCaptureMediaStream (y / o MediaRecorder) y no para la ventana. MediaRecorder podría ejecutarse a una velocidad de fotogramas diferente a la de la ventana (posiblemente a una velocidad no divisible regularmente, como 25 FPS frente a 60 FPS), por lo que quiero actualizar el lienzo a su velocidad de fotogramas en lugar de la ventana.