2016-11-18 26 views
1

CanvasCaptureMediaStream과 MediaRecorder를 사용할 때 각 프레임에서 이벤트를 가져 오는 방법이 있습니까?CanvasCaptureMediaStream/MediaRecorder 프레임 동기화

내가 필요한 것은 requestAnimationFrame()과 다르지 않지만 CanvasCaptureMediaStream (및/또는 MediaRecorder)이 필요하고 창은 필요하지 않습니다. MediaRecorder가 창과 다른 프레임 속도로 실행될 수 있습니다 (25FPS 대 60FPS와 같이 규칙적으로 나눌 수없는 비율로 가능할 수 있음). 따라서 창이 아닌 프레임 속도로 캔버스를 업데이트하려고합니다.

답변

3

이 예제 크롬 단순히 탭을 흐리게 캔버스 스트림을 중지하기 때문에 현재는 완전히, 파이어 폭스에서 작동은 ... (아마 this bug 관련,하지만 잘 내 타이머가 작동 아닌 것 같다) ... 기록

[편집] : 그들은 this bug 고정,하지만 더 이상 FF로 인해 this one이 (e10s에 의해 발생했기 때문에 실제로 지금) 만 크롬에서 작동합니다.


는 프레임이 어느 것도 MediaRecorder에, 그것을 렌더링 된 때 알려주의 MediaStream에 어떤 이벤트가 될 것 같지 않습니다.

MediaStream의 currentTime 속성 (현재 FF로만 제공됨)도 captureStream() 메서드에서 전달 된 fps 인수와 함께 변경되지 않는 것처럼 보입니다.

하지만 현재 탭에 포커스가 맞지 않을 때 (예 : rAF의 경우) 주파수가 느려지지 않는 신뢰할 수있는 타이머가 필요합니다.
다행히도 WebAudio API는 화면 새로 고침 빈도가 아닌 하드웨어 시계를 기반으로 high precision timer입니다.

그래서 우리는 시간 초과 루프를 사용할 수있어 탭이 흐릿 해져도 주파수를 유지할 수 있습니다.

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

 
\t @arg callback : a callback function 
 
\t \t with the audioContext's currentTime passed as unique argument 
 
\t @arg frequency : float in ms; 
 
\t @returns : a stop function 
 
\t 
 
*/ 
 
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 베네 :
이 예에서, 나는 초당 25에 주파수를 설정하지만, 우리는 초당 60 프레임으로 설정할 수 있으며, 심지어 내 옛날 노트북에서 제대로 작동하는 것 같다 최소한 간단한 애니메이션으로.

+0

흥미로운 창의적인 솔루션입니다. 나는 그것으로 실험 할 것이다. 감사! – Brad