Ajinkya
Ajinkya

Reputation: 81

Use Web Camera to capture profile pic and display the pic in canvas

I have a plugin where in I capture Image using Web camera present on the laptop or mobile and then place it in the canvas. All this works well in Chrome but when using Firefox , it simply doesn't work. I suspect its the navigator.getUserMedia which is causing the problem in firefox as it is deprecated.

link : https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getUserMedia

And Google developer suggests the use of navigator.getUserMedia and it is also compatible with my app.

link: https://developers.google.com/web/updates/2015/10/media-devices

So please do suggest what changes should be done in the below code for it to work in firefox.

Thanks in Advance.

<script type="text/javascript">
var ctx = null;
var canvas = document.getElementById("tmpImage");
var localMediaStream = null;
var video = document.querySelector('video');

function snapshot() {
    if (localMediaStream) {
        ctx.drawImage(video, 0, 0);
        var img = document.getElementById('CaptureImage');
        // "image/webp" works in Chrome 18. In other browsers, this will fall back to image/png.
        img.src = canvas.toDataURL('image/webp');
    }
}

function hasGetUserMedia() {
    // Note: Opera builds are unprefixed.
    return !!(navigator.getUserMedia || navigator.webkitGetUserMedia ||
        navigator.mozGetUserMedia || navigator.msGetUserMedia);
}

function onFailSoHard(e) {
    if (e.code == 1) {
        alert('User denied access to their camera');
    } else {
        alert('getUserMedia() not supported in your browser.');
    }
}

function start() {

    if (hasGetUserMedia()) {
        if (navigator.webkitGetUserMedia)
            navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
        //var getUserMedia = navigator.webkitGetUserMedia || navigator.getUserMedia;


        //var gumOptions = { video: true, toString: function () { return 'video'; } };    
        if (navigator.getUserMedia) {

            navigator.getUserMedia({
                video: true,
                audio: false
            }, function (stream) {
                if (navigator.webkitGetUserMedia) {
                    video.src = window.webkitURL.createObjectURL(stream);
                } else {
                    video.src = stream; // Opera
                }
                localMediaStream = stream;
            }, onFailSoHard);
        } else {
            video.src = 'somevideo.webm'; // fallback.
        }
    }
}

function stop() {
    video.pause();
    video = document.getElementById('sourcevid');
    video.src = "";
    localMediaStream.stop();
}

function ResizeCanvas() {
    canvas.height = video.videoHeight;
    canvas.width = video.videoWidth;
}

$(document).ready(function () {
    ctx = canvas.getContext('2d');
});

Upvotes: 1

Views: 1599

Answers (2)

jib
jib

Reputation: 42530

Use the official adapter.js polyfill. Problem solved.

E.g. this fiddle works in all supported browsers.

navigator.mediaDevices.getUserMedia({ video: true })
  .then(stream => video.srcObject = stream)
  .catch(e => console.error(e));

Supports modern constraints syntax as well.

Upvotes: 2

Kaiido
Kaiido

Reputation: 137171

Yes, getUserMedia API is evolving. The new syntax is navigator.mediaDevices.getUserMedia. Edge and Firefox, already implement this new syntax, that will return a Promise, forcing us to rewrite our codes...
Chrome is really late about it and even still uses some never standardized video constraint syntax. The process now becomes a bit complicated but there are some libraries that handle these cases.

I've also written my own implementation that should handle most GUM enabled browsers :

I'm not sure Chrome does allow getUserMedia from stack snippets so here is a jsfiddle

var video,canvas,ctx;
var settings = {
  video_constraints: {
    width: {
      min: 1200,
      max: 1920
    },
    height: {
      min: 720,
      max: 1080
    },
    require: ["width", "height"],
    facingMode: "user",
  },
  audio: false,
}

function getStream(video) {
  video.streaming = false;
  if (navigator.webkitGetUserMedia)
    setWebkitConstraints();
  navigator.getUserMedia = navigator.mediaDevices.getUserMedia || navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
  if (!navigator.getUserMedia && !navigator.mediaDevices) {
    alert('GUM is not supported by this browser');
    return false;
  }
  var opts = {
    video: settings.video_constraints,
    audio: settings.audio
  };
  var then = function(stream) {
    if (navigator.mozGetUserMedia)
      video.mozSrcObject = stream;
    else {
      var URL = window.URL || window.webkitURL;
      video.src = URL.createObjectURL(stream);
    }
    video.play();
    loopStart(video);
  };
  var error = function(err) {
    console.log("An error occured! ", err)
    if (err.name.indexOf('Permission') == 0) return;
  };

  if (navigator.mediaDevices) {
    navigator.mediaDevices.getUserMedia(opts).then(then, error).catch(error);
  } else {
    navigator.getUserMedia(opts, then, error);
  }
};
// handle webkit old and deprecated constraint syntax
var setWebkitConstraints = function() {
  var wkConstraints = {
    mandatory: {}
  };
  var c = settings.video_constraints;
  for (var i in c) {
    switch (i) {
      case 'width':
        for (j in c[i]) {
          switch (j) {
            case 'max':
              wkConstraints.mandatory.maxWidth = c[i][j];
              break;
            case 'min':
              wkConstraints.mandatory.minWidth = c[i][j];
              break;
            case 'exact':
              wkConstraints.mandatory.minWidth = wkConstraints.mandatory.maxWidth = c[i][j];
              break;
          }
        };
        break;

      case 'height':
        for (var j in c[i]) {
          switch (j) {
            case 'max':
              wkConstraints.mandatory.maxHeight = c[i][j];
              break;
            case 'min':
              wkConstraints.mandatory.minHeight = c[i][j];
              break;
            case 'exact':
              wkConstraints.mandatory.minHeight = wkConstraints.mandatory.maxHeight = c[i][j];
              break;
          }
        };
        break;
      default:
        break;
    }
  }
  settings.video_constraints = wkConstraints;
};
var loopStart= function(video){
		
		if (!video.streaming) {
			if(video.videoHeight === 0){
				window.setTimeout(function() {
					video.pause();
					video.play();
					loopStart(video);
					}, 100);
				}
			else {
				video.streaming = true;
				video.dispatchEvent(new Event('streaming'));
				}
			}else{return;}
		};

(function init(){
  video = document.createElement('video');
  canvas = document.createElement('canvas');
  document.body.appendChild(canvas);
  ctx = canvas.getContext('2d');
  video.addEventListener('streaming', copy2canvas, false);
  getStream(video);
  })()
function copy2canvas(){
	console.log('succesfully streaming');
    canvas.width = video.videoWidth;
    canvas.height = video.videoHeight;
    draw();
    }
function draw(){
    ctx.drawImage(video, 0,0);
    requestAnimationFrame(draw);
  }
canvas{border: 1px solid red}

Upvotes: 0

Related Questions