Edit April 15
As noted by @jib in his awesome answer,
Firefox [38+] does support a subset of constraints with
getUserMedia(), but not the outdated syntax that Chrome and Opera are
using. The mandatory / optional syntax was deprecated a year ago, and
minWidth and minHeight the year before that.
So the new syntax, approved by specs is :
var constraints = {
audio: false,
video: {
width: { min: 1024, ideal: 1280, max: 1920 },
height: { min: 576, ideal: 720, max: 1080 },
}
};
However this syntax throws an error in Chrome. As noted in comments, a PR to adapter.js
has been made, including a polyfill for older FF and chrome.
Here is my attempt, for chrome only (but newer version of FF seem to accept the magical and hidden require:['width', 'height']
.
var video_constraints = {
width: { min: 320, max: 480 },
height: { min: 240, max: 360 },
require: ["width", "height"] // needed pre-Firefox 38 (non-spec)
};
function getMedia(){
if(navigator.webkitGetUserMedia){
var wkConstraints={mandatory: {} };
var c = 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;
}
}
video_constraints = wkConstraints;
}
navigator.getUserMedia = ( navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia);
if(!navigator.getUserMedia){
alert("your browser doesn't support getUserMedia")
}
navigator.getUserMedia(
{
video: video_constraints,
audio: false,
},
function(stream) {
if (navigator.mozGetUserMedia) {
video.mozSrcObject = stream;
}
else {
var URL = window.URL || window.webkitURL;
video.src = URL.createObjectURL(stream);
}
video.play();
},
function(err) {
console.log(err);
}
);
}
var video= document.querySelector('video');
video.addEventListener('playing', loopStart, false);
function loopStart(){
this.removeEventListener('playing', loopStart);
if(this.videoHeight === 0){
window.setTimeout(function() {
this.pause();
this.play();
loopStart();
}, 100);
}
else {
this.setAttribute('width', this.videoWidth);
this.setAttribute('height', this.videoHeight);
}
}
getMedia();
<video/>
First Answer
So I started to write you this before you answered your own question.
As noted in the comments, I'm drawing each frame of the video to fit a resized canvas.
var video, canvas, streaming = false,
constrainedWidth = 320,
constrainedHeight = 180;
function streamCam() {
navigator.getMedia = (navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
//**Deprecated Now, see the update**
var video_constraints = {
"mandatory": {
"minWidth": constrainedWidth,
"minHeight": constrainedHeight,
"minFrameRate": "30"
},
"optional": []
}
navigator.getMedia({
video: video_constraints,
audio: false
},
function(stream) {
if (navigator.mozGetUserMedia) {
video.mozSrcObject = stream;
} else {
var vendorURL = window.URL || window.webkitURL;
video.src = vendorURL.createObjectURL(stream);
}
video.play();
},
function(err) {
console.log("An error occured! " + err);
streamCam();
}
);
}
function FFResize() {
canvas.width = constrainedWidth;
canvas.height = constrainedHeight;
canvas.getContext('2d').drawImage(video, 0, 0, constrainedWidth, constrainedHeight);
setTimeout(function() {
requestAnimationFrame(FFResize)
}, 10);
}
window.onload = function() {
video = document.querySelector('#video'),
canvas = document.querySelector('#canvas');
streamCam();
video.addEventListener('playing', function(ev) {
if (!streaming) {
if (video.videoHeight === 0) {
window.setTimeout(function() {
video.pause();
video.play();
}, 100);
} else {
video.setAttribute('width', video.videoWidth);
video.setAttribute('height', video.videoHeight);
canvas.setAttribute('width', constrainedWidth);
canvas.setAttribute('height', constrainedHeight);
streaming = true;
requestAnimationFrame(FFResize);
}
}
}, false);
};
#canvas {
position: fixed;
top: 0;
}
<video id="video"></video>
<canvas id="canvas"></canvas>
This does its job but as you noted constraints are still in dev and the only way to have them to work with Firefox is to manually set every browser's media.navigator.video.default_
in about:config
.