この例は現在のところ FireFoxでのみ完全に機能します。これは、タブがぼやけているときにクロムが単にキャンバス ストリームを停止するためです... (おそらくこのバグに関連していますが、タイマーは機能しているようですが、記録はしていないようです...)
[編集] :このバグが修正されたため、実際にはクロムでのみ機能するようになりましたが、これにより FF では機能しなくなりました( e10s が原因)。
MediaStream には、フレームがいつレンダリングされたかを知らせるイベントはないようです。MediaRecorder にもありません。
MediaStream (現在は FF でのみ使用可能)のプロパティでさえ、メソッドcurrentTime
で渡された fps 引数に応じて変化していないようですcaptureStream()
。
しかし、あなたが望んでいるように見えるのは、信頼できるタイマーです。つまり、現在のタブがフォーカスされていない場合 (rAF で発生します)、その頻度を失うことはありません。
幸いなことに、WebAudio API には、画面のリフレッシュ レートではなく、ハードウェア クロックに基づく高精度のタイマーもあります。
そのため、タブがぼやけている場合でも、その周波数を維持できる別のタイミング ループを使用できます。
/*
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)
};
btn.onclick = start;
<button id="btn">begin</button>
<canvas id="canvas" width="500" height="200"></canvas>
Nota Bene :
この例では、周波数を 25 fps に設定していますが、60 fps に設定することもできます。少なくともこのような単純なアニメーションでは、古いノートブックでも正しく動作するようです。