В настоящее время этот пример полностью работает только в FireFox, поскольку хром просто останавливает поток холста, когда вкладка размыта ... (вероятно, связано с эта ошибка, но, похоже, мой таймер работает, но не запись ... )
[Edit]: теперь он работает только в Chrome, так как они исправили эта ошибка, но больше не в FF из-за этот (вызванный e10s).
Похоже, что в MediaStream нет какого-либо события, сообщающего вам, когда в него был отрисован кадр, ни в MediaRecorder.
Даже свойство currentTime
в MediaStream (в настоящее время доступно только в FF), похоже, не меняется соответственно с аргументом 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 кадров в секунду, но мы можем установить ее на 60 кадров в секунду, и, похоже, она работает правильно даже на моем старом ноутбуке, по крайней мере, с такой простой анимацией .
person
Kaiido
schedule
19.11.2016