Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
413 views
in Technique[技术] by (71.8m points)

javascript - Canvas recording using captureStream and mediaRecorder

How can i record streams from more than one canvas? ie, when i change one canvas to other it has to record the active canvas continue to the first.

I have done like this:

stream = canvas.captureStream();
mediaRecorder = new MediaRecorder(stream, options);
mediaRecorder.ondataavailable = handleDataAvailable;
mediaRecorder.start(10);

function handleDataAvailable(event) {
  recordedBlobs.push(event.data);
}

But when adding another stream, only the first part is recorded. I'am pushing recorded data to a global array.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In the current implementations, you can't switch the recorded tracks of a MediaRecorder's stream.

When you try to do so, Firefox throws you in the console that

MediaRecorder does not support recording multiple tracks of the same type at this time.

while Chrome keeps silent and records black frames instead of the second track...

var canvases = Array.prototype.slice.call(document.querySelectorAll('canvas')),
  recordingStream,
  current = 0,
  chunks = [],
  recorder,
  switchInterval;


function startRecording() {

  // first gather both canvases streams & extract the videoTracks
  let streams = canvases.map((c) => {
    return c.captureStream(30)
  });
  let tracks = streams.map((s) => {
    return s.getVideoTracks()[0]
  });
  // create a new MediaStream with both tracks in it
  // we don't use addTrack because of https://bugzilla.mozilla.org/show_bug.cgi?id=1296531
  recordingStream = 'MediaStream' in window && new MediaStream(tracks) || new webkitMediaStream(tracks);

  // init the MediaRecorder
  recorder = new MediaRecorder(recordingStream);
  recorder.ondataavailable = saveChunks;
  recorder.onstop = exportVideo;
  recorder.onerror = (e) => {
    console.log(e.name)
  };
  recorder.start();

  stopRec.disabled = false;
  // switch the canvas to be recorder every 200ms
  switchInterval = setInterval(switchStream, 200);

}


// switch mute one of the tracks, then the other
function switchStream() {
  current = +!current;
  var tracks = recordingStream.getVideoTracks();
  tracks[current].enabled = true;
  // commented because it seems FF doesn't support canvasTrack's method yet
  // doesn't work in chrome even when there anyway
  //  tracks[current].requestFrame(); 
  tracks[+!current].enabled = false;
}

function saveChunks(evt) {
  // store our video's chunks
  if (evt.data.size > 0) {
    chunks.push(evt.data);
  }

}

stopRec.onclick = function stopRecording() {
  if (recorder.state !== 'recording') {
    this.disabled = true;
    return;
  }
  // stop everything
  recorder.stop(); // this will trigger exportVideo
  clearInterval(switchInterval);
  stopCanvasAnim();
  a.style.display = b.style.display = 'none';
  this.parentNode.innerHTML = "";
}


function exportVideo() {
  //  we've got everything
  vid.src = URL.createObjectURL(new Blob(chunks));
}



var stopCanvasAnim = (function initCanvasDrawing() {
  // some fancy drawings

  var aCtx = canvases[0].getContext('2d'),
    bCtx = canvases[1].getContext('2d');

  var objects = [],
    w = canvases[0].width,
    h = canvases[0].height;
  aCtx.fillStyle = bCtx.fillStyle = 'ivory';

  for (var i = 0; i < 100; i++) {
    objects.push({
      angle: Math.random() * 360,
      x: 100 + (Math.random() * w / 2),
      y: 100 + (Math.random() * h / 2),
      radius: 10 + (Math.random() * 40),
      speed: 1 + Math.random() * 20
    });
  }
  var stop = false;
  var draw = function() {

    aCtx.fillRect(0, 0, w, h);
    bCtx.fillRect(0, 0, w, h);
    for (var n = 0; n < 100; n++) {
      var entity = objects[n],
        velY = Math.cos(entity.angle * Math.PI / 180) * entity.speed,
        velX = Math.sin(entity.angle * Math.PI / 180) * entity.speed;

      entity.x += velX;
      entity.y -= velY;

      aCtx.drawImage(imgA, entity.x, entity.y, entity.radius, entity.radius);
      bCtx.drawImage(imgB, entity.x, entity.y, entity.radius, entity.radius);

      entity.angle++;
    }
    if (!stop) {
      requestAnimationFrame(draw);
    }
  }


  var imgA = new Image();
  var imgB = new Image();
  imgA.onload = function() {
    draw();
    startRecording();
  };
  imgA.crossOrigin = imgB.crossOrigin = 'anonymous';
  imgA.src = "https://dl.dropboxusercontent.com/s/4e90e48s5vtmfbd/aaa.png";
  imgB.src = "https://dl.dropboxusercontent.com/s/rumlhyme6s5f8pt/ABC.png";

  return function() {
    stop = true;
  };
})();
<p>
  <button id="stopRec" disabled>stop recording</button>
</p>
<canvas id="a"></canvas>
<canvas id="b"></canvas>
<video id="vid" controls></video>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...