Search code examples
javascripthtmlcanvasgetusermedia

Get back video format after <canvas>


Is there way to get the video from webcamera (getUserMedia), pass it to canvas, make some effects with this video and get back in video format (mp4 for example)?

I'm looking for a way to be done on client side only. And also it should be a real time process.


Solution

  • Yes you can, in modern browsers, but you'll loose every audio stream (Actually you can save it too), and I think that the mp4 requirement is not here yet and you should not wait for it (damn royalties) only webm or ogv export is currently available.

    You can use a MediaRecorder and the canvas.captureStream() method.

    var mediaRecorder = new MediaRecorder(canvas.captureStream(30));

    Here is an example code (which will only work on latests FF and chrome !).

    var startRecording = function(){
      // make something happen on the canvas
      var stopCanvas = initCanvasDrawing();
    
      // really, that's it..
      var recorder = new MediaRecorder(canvas.captureStream(30))
      var chunks = [];
      recorder.ondataavailable = function(e){
        if(e.data.size){
          chunks.push(e.data)
          }
      };
      recorder.onstop = function(){
    
        var blob = new Blob(chunks);
        var url = URL.createObjectURL(blob);
        
        unrelatedDOMStuff(url);
    
        stopCanvas();
        };
      recorder.start();
      
      setTimeout(function(){recorder.stop()}, 5000);
      }
    
    // the rest of the code is just for the demo
    
    var unrelatedDOMStuff = function(url){
        rec.style.display = canvas.style.display = 'none';
        var vid = document.createElement('video');
    
        vid.src = url
        vid.controls = true;
        document.body.appendChild(vid);
        vid.play();
        var a = document.createElement('a');
        a.innerHTML = 'you can also get it here';
        a.download = 'awesomeCanvasVid.webm';
        a.href = url;
        document.body.appendChild(a);
      }
    
    var initCanvasDrawing = function() {
    
      var ctx = canvas.getContext('2d');
    
      var objects = [];
      ctx.fillStyle = 'ivory';
      // taken from https://stackoverflow.com/a/23486828/3702797
      for (var i = 0; i < 100; i++) {
        objects.push({
          angle: Math.random() * 360,
          x: 100 + (Math.random() * canvas.width / 2),
          y: 100 + (Math.random() * canvas.height / 2),
          radius: 10 + (Math.random() * 40),
          speed: 1 + Math.random() * 20
        });
      }
      var stop = false;
      var draw = function() {
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        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;
    
          ctx.drawImage(img, entity.x, entity.y, entity.radius, entity.radius);
          entity.angle++;
        }
        if (!stop) {
          requestAnimationFrame(draw);
        }
      }
    
    
      var img = new Image();
      img.onload = draw;
      img.crossOrigin = 'anonymous';
      img.src = "https://dl.dropboxusercontent.com/s/4e90e48s5vtmfbd/aaa.png";
    
      return function() {
        stop = true;
      };
    }
    
    startRecording();
    #rec{ width:2em; height:2em; border-radius:50%; background-color:red; position: absolute; top: 0; left: 0;}
    a{display: block;}
    video{border:1px solid green;}
    <canvas id="canvas" width="500" height="250"></canvas>
    <div id="rec"></div>

    Note that since webm video format doesn't support transparency, every transparent pixels will be set to opaque black.