Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force a 16:9 ratio with getUserMedia on all devices?

I need to use getUserMedia while the video is set to record in 16:9 resolution.

My code works on most desktops and on Android 7 and above:

navigator.getUserMedia( {
   audio: true,
   video: {
      mandatory: {
          minWidth: 380,
          minHeight: 214,
          maxWidth: 380,
          maxHeight: 214
      }
   }
})

But on Android 6 and below, and on some desktops too (can't figure out exactly which), getUserMedia breaks, and no image is available from the camera.

This works on all devices and desktop, but with a default resolution ratio of 4:3, while I need 16:9:

navigator.getUserMedia( {
   audio: true,
   video: true
})

I tried omitting the mandatory, no luck.

To add to my confusion, iOS devices (11 beta) and Android require passing the facingMode argument:

video: { facingMode: 'user' }

So, it seems that passing the width and height arguments breaks getUserMedia on some desktops and devices like Android 5 and 6.

Is there a way to force a 16:9 ratio on all devices? What is the correct and conventional method of capturing a video with specific dimensions?

like image 511
Koby Douek Avatar asked Aug 20 '17 11:08

Koby Douek


1 Answers

You're assuming all cameras support 16:9, or that all browsers will crop the video for you. Not so. You're also using an outdated API. Try the latest API (fiddle, samples):

var constraints = {video: {width: 320, height: 180, facingMode: "user"}};

navigator.mediaDevices.getUserMedia(constraints)
.then(stream => video.srcObject = stream)
.then(() => new Promise(resolve => video.onloadedmetadata = resolve))
.then(() => log(video.videoWidth +"x"+ video.videoHeight))
.catch(e => console.log(e));

getUserMedia at its heart is a camera/mic discovery API: All the min, max, exact, ideal keywords exist to describe your constraints, i.e. your tolerance for not getting what you want.

I would suggest the aspectRatio constraint, except nobody implements that yet, and it's just another constraint to decrease your tolerance.

At the moment I believe only Chrome will downscale and crop camera output to the exact size you want. Turns out this is what most people want, but discovers little about the user's camera. Other browsers may follow, since there hasn't been much demand for much else, but they don't currently downscale.

Note though that even Chrome won't upscale, so if you're using Chrome on Android, there's a chance you asked for a higher resolution than your Android 6 device can output. Check for OverconstrainedError in this case, and try again with lower values.

In short, you're not always going to get the exact size you want, as it ultimately depends on the user's camera and their browser.

But HTMLVideoElement downscales on playback anyway, and you can use CSS to crop.

like image 103
jib Avatar answered Nov 17 '22 17:11

jib