CanvasCaptureMediaStream/MediaRecorder फ़्रेम सिंक्रोनाइज़ेशन



html5-canvas web-mediarecorder (1)

CanvasCaptureMediaStream और CanvasCaptureMediaStream का उपयोग करते CanvasCaptureMediaStream , क्या प्रत्येक फ्रेम पर एक घटना प्राप्त करने का एक तरीका है?

जो मुझे चाहिए वह requestAnimationFrame() विपरीत नहीं है, लेकिन मुझे इसे CanvasCaptureMediaStream (और / या MediaRecorder) के लिए चाहिए न कि विंडो के लिए। MediaRecorder विंडो की तुलना में एक अलग फ्रेम दर पर चल सकता है (संभवतः नियमित रूप से विभाज्य दर पर नहीं, जैसे कि 25 FPS बनाम 60 FPS), इसलिए मैं विंडो के बजाय अपने फ्रेम दर पर कैनवास को अपडेट करना चाहता हूं।


यह उदाहरण वर्तमान में केवल पूरी तरह से फ़ायरफ़ॉक्स पर काम करता है , क्योंकि क्रोम बस कैनवास स्ट्रीम को रोकता है जब टैब धुंधला हो जाता है ... (शायद इस बग से संबंधित है, लेकिन ठीक है, मेरा टाइमर काम कर रहा है, लेकिन रिकॉर्डिंग नहीं ...)

[संपादित करें] : यह वास्तव में अब केवल क्रोम में काम करता है, क्योंकि उन्होंने इस बग को ठीक कर दिया है, लेकिन इस एक के कारण एफएफ में अब और नहीं (ई 10 के कारण)।

MediaStream पर कोई भी घटना प्रतीत नहीं होती है, जो आपको बताती है कि एक फ्रेम को कब प्रस्तुत किया गया है, न ही MediaRecorder पर।

यहां तक ​​कि MediaStream की वर्तमान समय की संपत्ति (वर्तमान में केवल FF में उपलब्ध है) currentTime captureStream() विधि में पारित एफपीएस तर्क के साथ तदनुसार परिवर्तित नहीं होती है।

लेकिन आप जो चाहते हैं, वह एक विश्वसनीय टाइमर है, जो कि इसकी आवृत्ति को ढीला नहीं करेगा, जब कि वर्तमान टैब केंद्रित नहीं होता है (जो कि rAF के लिए होता है)।
सौभाग्य से, वेबएडियो एपीआई में एक उच्च परिशुद्धता वाला टाइमर भी होता है, जो स्क्रीन रिफ्रेश दर के बजाय हार्डवेयर क्लॉक पर आधारित होता है।

तो हम एक वैकल्पिक समयबद्ध लूप के साथ आ सकते हैं, टैब के धुंधला होने पर भी इसकी आवृत्ति को बनाए रखने में सक्षम।

/*
	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>

नोटा नेने :
इस उदाहरण में, मैंने आवृत्ति को 25fps पर सेट किया है, लेकिन हम इसे 60fps पर सेट कर सकते हैं और यह मेरे पुराने नोटबुक पर भी सही ढंग से काम करने लगता है, कम से कम ऐसे सरल एनीमेशन के साथ।





web-mediarecorder