• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar
  • Skip to footer
webrtcHacks

webrtcHacks

guides and information for WebRTC developers

  • Home
  • Livestream
  • About
    • Chad Hart
    • Philipp Hancke
  • Subscribe
  • Merch
  • Contact
  • Show Search
Hide Search

Guide Brief, camera, getUserMedia, resolution Chad Hart · August 26, 2014

WebRTC Video Resolutions 2 – the Constraints Fight Back

Note: See February 2016 update here.

{“editor”, “chad“}


Taking apart WebRTC camera resolution constraints part II. Photo courtesy of Flikr user Chia Wei Ong

Last October I did a post on some quirks I found when applying camera resolutions constraints with getUserMedia. Surprisingly I found the resolutions that were returned were sometimes different than what you ask for, even if you make your constraints mandatory. Firefox didn’t support programmable video resolution constraints at all.

That was a while ago, so earlier this summer I checked my getUserMedia camera resolution finder again. This time Chrome 36 passed all my tests:

Ask Chrome 30 Chrome 36
1280×720 pass: 1280×720 pass: 1280×720
960×720 pass: 960×720 pass: 960×720
640×480 pass: 640×480 pass: 640×480
640×360 fail: 320×180 pass: 640×360
320×240 pass: 320×240 pass: 320×240
320×180 fail: 160×88 pass: 320×180

Constraint handling has clearly changed, but how? I could not find any coherent documentation on this, so I decided to update my resolution scanning code and re-run my analysis to empirically determine how mandatory constraints are handled.  If you choose to read-on below, you’ll see much has been fixed, but there are still a few nagging issues.

Recap from last October

If you want to skip my How to Figure Out WebRTC Camera Resolutions post from last October, then here is a quick summary:

  • I was looking for a specific resolution, so I set mandatory constraints with maximum and minimum values that were the same (as opposed to asking for a range)
  • Chrome had a set list of 6 resolutions it chose from behind the scenes
  • If you asked for something that was not one of these resolutions then you would get an error
  • If you asked for one of these six sometimes what you got would be different

Now that we are done with that history, let’s walk through my latest tests.

Methodology

I rewrote my original code (see the next section) and conducted new full resolution scans of every 4:3 and 16:9 resolution combination between 2160 vertical pixels and 1. I tried doing some tests on Firefox, but you still need to manually set your resolutions if you want something different than 640×480, so I did not focus my tests there. I also did some quick test on Opera 23 on desktop – it appeared to responded just like Chrome 36, in fact it identified itself as Chrome 36, but I did not do an extensive analysis of this. My results below are focused on Chrome across desktop and mobile.

Tests methodology summary:

Vertical Resolutions scanned 1 to 2160
Aspect ratios included 16:9, 4:3
Browsers Chrome 36 desktop, Chrome 36 mobile, Chrome Canary 39, Chrome 37 mobile
Operating systems Windows 8, Chrome OS, OS X

Results can fall into one of 4 categories:

  1. Pass – the resulting stream output has the same resolution of what was asked for in the mandatory constraints
  2. TrackStartError – this happens in Chrome 36 & 37 if the stream cannot be captured for any reason. I assumed it was because of my mandatory constraints
  3. ConstraintNotSatisfiedError – this is a newer, more useful error that has been specified and is used in Chrome 39
  4. Mismatch – this is my programs own error which is tagged whenever the output resolution is different from what was asked for in the mandatory constraints

Note my scanning code was occasionally buggy on Chrome 36 when doing long scans. I would randomly get a 2×2 resolution returned or intermittent track failed responses. I am sure I have some race conditions in my code that are causing this, but it does not appear to happen as often in Chrome 37 or 39. In these cases I manually verified the resolution and corrected the results accordingly.

You can run the tests yourself with my new scanner here.

Code updates

Please see the original How to Figure Out WebRTC Camera Resolutions post for a walk through on how to adjust constraints and use getUserMedia with different camera resolutions. I didn’t make any major changes to my methodology from last time, but I did make several modifications to improve the functionality to help with testing including:

  • Using jQuery
  • Redirect to https
  • Device enumeration and selection if your browser supports it
  • Optional predefined set of common resolutions for a “quick” scan
  • More complete scanning of every 16:9 and 4:3 resolution within a user-defined range
  • Used the official adapter.js to normalize browser differences & help with identification
  • Clicking on a row after the test is done reloads that resolution
  • Dump results to JSON or CSV

The only real WebRTC specific improvement was on the Device Enumeration. I hope to do a separate post on that to cover camera selection in more detail after I dig into the newer NavigatorUserMedia.getMediaDevices API. I kept with the existing vs. MediaStreamTrack.getSources for device enumeration now.

You can check out my complete code on github.

Result data

This took a while to compile – scanning 4320 different resolutions can take hours depending on the device. Here is a quick summary table of my results:

Device Max Res Ratio Pass (range) Fail (reason: range)
Chrome 36
camera 0, facing back 4K 16:9 120-198, 240-1080 TrackStart: <120, 199-239, >1080
4:3 120-1080 TrackStart: <120, >1080
camera 1, facing front UXGA 16:9 120-198, 240-1080 TrackStart: <120, 199-239, >1080
4:3 120-1080 TrackStart: <120, >1080
FaceTime HD Camera 720p 16:9 90-720 TrackStart: <90, >1080; Mismatch: 721-1080
4:3 90-720 TrackStart: <90, >1080; Mismatch: 721-1080
HP TrueVision HD 720p 16:9 60-90, 120-180, 240-720 TrackStart: <60,181-239, >720
4:3 60-800 <60, >800
Microsoft LifeCam Studio 1080p 16:9 60-90, 120-1080 <60, 91-119, >1080
4:3 60-1080 <60, >1080
WebCam SC-03FFM12339N VGA 16:9 60-99, 120-198, 240-360 <60,100-119, 199-239, >361
4:3 60-480 <60, >480
Chrome 37
camera 0, facing back 4K 16:9 <=1080 NotSatisfied: >1080
4:3 <=1080 NotSatisfied: >1080
camera 1, facing front UXGA 16:9 <=1080 NotSatisfied: >1080
4:3 <=1080 NotSatisfied: >1080
Chrome 39
FaceTime HD Camera 720p 16:9 <=720 NotSatisifed: <90, >1080; Mismatch: 721-1080
4:3 <=720 NotSatisifed: <90, >1080; Mismatch: 721-1080
HP TrueVision HD 720p 16:9 <=720 NotSatisfied: >720
4:3 <=800 NotSatisfied: >800
Microsoft LifeCam Studio 1080p 16:9 <=1080 NotSatisfied: >1080
4:3 <=1080 NotSatisfied: >1080

If you want to see the full aggregated results dump in a single table from all my tests, you can find that here.

Findings

It is a little difficult to parse the table above, but these results are much closer to what I would expect vs. my results last time. Here are some highlights:

  • 1080p is the new max  – Chrome (and Opera) now support 1080p. It used to be 720p. All my cameras that support 1080p were able to show this “full HD” resolution and the difference is definitely noticeable on a large screen. Oddly, my MacBook pro accepted 1080p constraints, but returned a 720p resolution.
  • No 4K support today – I was also curious to see if 4K would work since my Galaxy S5 supports 4K video recording. 4K normally corresponds to a 3840 x 2160 resolution, so I started my tests with a 2160 vertical resolution. Unfortunately I had no luck – 1080p was the highest I was able to go.
  • New video scaling – Chrome used to give you resolutions different than what you specified in a “mandatory” constraint object. Now Chrome appears to scale the output video (as measured by the videoWidth and videoHeight properties) what is passed to the  in most cases. I still got many no-start failures, but the only mismatch I got was on my MacBook Pro, and that was only on vertical resolutions between 720 and 1080.
  • No random TrackFail ranges in Chrome 37+ – If you look at the results above for Chrome 36 , you see there are many small, seemingly random resolution ranges that are not allowed.  The Chrome Canary build is presently Chrome 39 and Chrome Beta on Android is on version 37. Using 37 and 39 you see that anything between 1 and the camera’s maximum resolution returns a video stream with the requested resolution.
  • Chrome 39 uses new ConstraintNotSatisfiedError – My Chrome 36 & 37 tests would usually return a TrackStartError message when the constraints were not satisfied. Chrome 39 returns a much more meaningful ConstraintsNotSatisfiedError instead. I did not receive any TrackStartError messages in any of my Chrome 39 tests. [reference updated constraints spec & emails]
  • Micro-resolutions in Chrome 39 – Unlike earlier versions, Chrome 37 and higher appear to have no lower resolution floor.  I am not sure you can do much with a 1×1 video stream, but Chrome will let you do it.
  • Mobile device orientation affected my results – getUserMedia returned a squarish aspect ratio (1 to 1.33) against what I asked for in my constraints whenever I had my GS5 vertically oriented. This happened in Chrome 36 & 27. Everything worked fine when it was horizontal. Tsahi ran this on his Nexus 4 and had the same results. I have no idea if this is an issue with Android itself or something in Chrome.
Galaxy S5 showing camera constraint test screen capture
Galaxy S5 camera constraint scans worked when the device was horizontally oriented.
Galaxy S5 showing camera image
Galaxy S5 showing camera constraint errors when the device was vertically oriented.

To verify I didn’t do something wrong, I did some checks against the Google Chrome’s getusermedia-resolution sample. I noticed here that only a maximum or minimum mandatory constraint was set. When I modified the sample to add both maximum and minimum constraints, I had the same result.

1
2
3
4
5
6
7
8
9
10
11
var hdConstraints = {
    video: {
        mandatory: {
            minWidth: 1280,
            minHeight: 720,
            /*Added by Chad*/
            maxWidth: 1280,
            maxHeight: 720
        }
    }
};

You can see my jsfiddle for reference.

Actually, experimenting with the original getusermedia-resolution sample I also get weird results. The constraints are set to  minWidth: 1280, minHeight: 720  but the output shows 720×1280 when I have my GS5 vertically oriented:

My GS5 showing weird results with getusermedia-resolution's minimum constraints (Chrome Andriod 37)
My GS5 showing weird results with getusermedia-resolution’s minimum constraints (Chrome Android 37)

This is just speculation, but playing around with GoogleChrome’s original sample, I suspect my GS5 is adjusting the orientation of the video automatically (width<->height) but the videoWidth and videoHeight properties are not being flipped accordingly. I’ll put an inquiry in and report back.

So Are the Camera Constraint Issues Fixed?

Mostly. Chrome 36 is much better than my old Chrome 30 tests, but leaves a lot to be desired. However, if you just want a video stream with a very specific resolution then this appears to be more-or-less fixed in Chrome 39. The only open issue I see are:

  • my Macbook returning 720p when asking for 1080p instead of giving a ConstraintsNotSatisfiedError
  • my GS5 behaving oddly with a vertical device orientation

Ultimately I would advise against using both max and minimums of the same value to make sure you get exactly what you ask for. Using a range or just using optional is probably a safer bet unless you absolutely need a specific resolution.

You still need to Check the Specs

It looks like there are some changes coming in the future.  The constraint syntax has changed slightly in the constraints draft, but this has not been updated in Chrome just yet (as of 38) – see this Chromium thread for details.

If these are issues that matter to you, also make sure to monitor the getUserMedia draft too which was updated earlier this month.

Lastly, my example above only deals with changing resolutions locally. This becomes more complicated when you want the remote party wants the sender to change resolutions. The constraints draft covers some options there.

{“author”: “chad“}

 

Editor’s update

Miguel from Google provided some helpful clarifications in the comments below:

To add to this post:

  • the resolutions supported by the Capture Device(s) are listed in chrome://media-internals — after the user having allowed at least once either capture or device listing (e.g. [1] and click on “Get Devices”).
  • Chrom(ium) will try to get from that list the closest resolution to the one requested by the user, in terms of “amount of pixels distance”, yet still with each dimension >= than the requested. The captured video frames will be cropped if needed.
  • Sometimes cameras do not enumerate correctly depending on the combination of OS version, vendor/kernel support and API arcanes, in that case Chrome will fall back to a list of precooked, widely supported resolutions.
  • Sadly there’s no way to get the supported resolution list from JavaScript, although it can be retrieved from a Chrome App.

[1]https://src.chromium.org/svn/trunk/src/chrome/test/data/webrtc/manual/peerconnection.html

Guide Brief, camera, getUserMedia, resolution

Related Posts

  • How to Figure Out WebRTC Camera ResolutionsHow to Figure Out WebRTC Camera Resolutions
  • getUserMedia resolutions III – constraints unleashedgetUserMedia resolutions III – constraints unleashed
  • Fix Bad Lighting with JavaScript Webcam Exposure Controls (Sebastian Schmid)Fix Bad Lighting with JavaScript Webcam Exposure Controls (Sebastian Schmid)
  • Guide to WebRTC with Safari in the Wild (Chad Phillips)Guide to WebRTC with Safari in the Wild (Chad Phillips)

RSS Feed

Reader Interactions

Comments

  1. Philipp Hancke says

    August 26, 2014 at 5:12 pm

    “Micro-resolutions in Chrome 39 – Unlike earlier versions, Chrome 37 and higher appear” — I think that might be caused by https://code.google.com/p/chromium/issues/detail?id=346616#c11

    Awesome post!

    Reply
  2. Michael Graves says

    October 8, 2014 at 5:00 pm

    I’m puzzled by your reference to the Microsoft Lifecam Studio as being 1080p capable. I don’t believe that it’s produces 1080p video. MS is unclear on the matter as they claim it has a 1080p sensor, but that it’s capable of “720p video chat.”

    As a USB 2.0 connected camera without an onboard encoder it cannot pass uncompressed 1080p frames at rate that many people would consider “video.”

    Webcams that are 1080p capable, like the Logitech C920, C930e, BBC950 and CC3000e have an onboard encoder chip that compresses the frames using either MJPEG or H.264. The software that init’s the camera needs to know about these modes in order to correctly init the camera to deliver a compressed stream.

    Reply
    • Chad Hart says

      October 10, 2014 at 9:55 am

      I read the same reviews about quasi-1080p support on the Lifecam Studio, but did not think much about it since Chrome only used to do 720p. All I can say I did a getUserMedia request with mandatory constraints asking for 1920×1080 and it returned a stream that was 1920×1080. The Chrome FPS monitor indicates it is running at 20 FPS.

      I just did this quick test:
      https://www.dropbox.com/s/ft75cw4g821bu9y/Lifecam%201080p%20check.png?dl=0

      I guess it is possible Chrome is stretching the image, but it does appear to be clearer than a normal 720p stream. Also, Chrome does not stretch for resolutions above 1080p, or on other cameras above 720p, so it seems odd it would stop at 1080p.

      I will do some more tests and let you know if I find anything interesting.

      Reply
  3. James Morley says

    October 23, 2014 at 5:01 am

    Hi, I’ve been doing some research for a project looking at providing a cheap, reliable ‘digitisation’ solution for family heritage projects, something that could be set up in libraries, local history society events etc. If I can get good quality 1080p still images from a webcam and a browser interface, that starts to become realistic and would be an amazing step forward compared to tethered digital SLRs and bespoke software.

    So, my questions are:
    – for testing, what sort of webcam is currently available that might let me test this? I note the comments above that say the Microsoft one is not true 1080p, and the Logitech ones compress, which implies some sort of degradation in quality for stills at least
    – how soon do you think the browser technology will move forward to a stage where 4k might be possible, and what devices exist to capture this? Could a 4k phone camera like the S5 be rigged up to an external device?

    If you think I am going up the wrong road for this then do let me know!

    Thanks, James

    Reply
    • Chad Hart says

      October 23, 2014 at 10:02 am

      I did not state this clearly, but camera 0 and camera 1 in the result data was my Galaxy S5. I tried doing a 4K capture but I could only get up to 1080p.

      I am not sure if you will be able to get consistent high-quality images from WebRTC today. However, I think this situation is improving. First, I would look into the Camera API. I have not tried any of this, but you can see some details on this here: https://developer.mozilla.org/en-US/docs/Web/Guide/API/Camera It looks like this is more of a mobile solution.

      I have not heard any statements on this, but I would guess increasing WebRTC’s maximum resolution to 4K will make more sense in Chrome when they add VP9 support for WebRTC. Justin stated this would happen by the end of the year (see Tsahi’s summary here).

      As I talk about in my first WebRTC Camera Resolutions post, Firefox does not let you dynamically change the resolution, but you can manually adjust the settings. I have not tried manually specifying a 1080p or 4K resolution tests in Firefox’s navigator.media.video settings, but that would be a good experiment.

      Lastly, some of the ORTC recommendations could make specifying different media parameters. However, taking high quality photos is not in the initial target applications for ORTC.

      Reply
  4. Matthias Doering says

    December 8, 2014 at 6:58 am

    Really good post.

    But I have some trouble with the correct identification of some resolutions. I run Chrome 40 with a Logitech C310 camera.

    The highest resolution which are supported by the camera is sometimes listened and sometimes not. 720p@16:9 is a problem. I get this resolution just if I clone your code locally and run it via http (with manual confirmation of the camera Access for each Resolution test). Then it appears on the list as “passed” and may be selected and get displayed in the Video window.

    When running the https test this Resolution sometimes passes and sometimes not (fail: mismatch).

    Regards
    Matthias

    Could be a timing Problem because the timing is quite different when I must manually confirm the camera access when using http instead of https.

    Reply
    • Chad Hart says

      December 14, 2014 at 10:38 pm

      Thanks for the comment Matthias. Yes – I notice this very infrequently on some large scans too.

      To start out I would recommend changing line 220 of resolutionScan.js to a value greater than 100, like 200, to see if this helps.

      Better would be to identify a more reliable event trigger before reading the resolution from the video element. I was unable to find one, thus the “100 ms” delay I added on line 220.

      It may also be better to not use jQuery to bind to the event to minimize the delay.

      Reply
  5. Luong says

    February 24, 2015 at 10:42 am

    Thank you so much for this great post.

    Reply
  6. Miguel Casas Sanchez says

    April 20, 2015 at 9:02 pm

    To add to this post:
    – the resolutions supported by the Capture Device(s) are listed in chrome://media-internals — after the user having allowed at least once either capture or device listing (e.g. [1] and click on “Get Devices”).
    – Chrom(ium) will try to get from that list the closest resolution to the one requested by the user, in terms of “amount of pixels distance”, yet still with each dimension >= than the requested. The captured video frames will be cropped if needed.
    – Sometimes cameras do not enumerate correctly depending on the combination of OS version, vendor/kernel support and API arcanes, in that case Chrome will fall back to a list of precooked, widely supported resolutions.
    – Sadly there’s no way to get the supported resolution list from JavaScript, although it can be retrieved from a Chrome App.

    [1] https://src.chromium.org/svn/trunk/src/chrome/test/data/webrtc/manual/peerconnection.html

    Reply
    • Chad Hart says

      April 20, 2015 at 10:33 pm

      Thanks for sharing Miguel! This is very helpful – let me amend the post to include your comments.

      Reply
  7. Matt Bo says

    October 6, 2015 at 5:50 am

    hi,

    thanks for your great work!!

    one question:
    when I start your scan, your program get access to my webCam without asking me if it can.
    how did you do this?
    In my project the call of getUserMedia leads to the pop-up where the user have to give the ok for the access to the webCam.

    regards
    Matt

    Reply
    • Chad Hart says

      October 9, 2015 at 8:53 pm

      Thanks Matt.

      I am using HTTPS. When you use HTTPS Chrome will default to automatically allowing subsequent access unless you change this global default in the settings. I cover that a bit in the original post on this topic: https://webrtchacks.com/how-to-figure-out-webrtc-camera-resolutions/

      Make sure you use HTTPS – pretty soon you will not be able to use getUserMedia unless you do: https://groups.google.com/forum/#!topic/discuss-webrtc/uMWoBvCceSg

      Reply
  8. Chad Hart says

    March 5, 2016 at 9:34 am

    I updated the scanner, added Edge, ran new scans, and made some new findings to this post here:

    Reply
  9. Avijit Sarkar says

    May 1, 2016 at 12:02 pm

    How do i auto select the best available resolution?

    Reply
    • Chad Hart says

      May 2, 2016 at 11:34 pm

      By best available, do you mean highest? Note that higher resolutions often result in lower frame rate capabilities. Definitely check out the update to this post here: https://webrtchacks.com/getusermedia-resolutions-3/

      There is no way to ask for “give me the highest available” in implementations today. If you check out the Media Capture and Streams spec, something closer to this is coming, but I don’t believe anyone has implemented it yet.

      Generally the browsers provide the best available resolution they can determine if you provide a realistic range. Manually trying to determine what is available with something like the scanner I made definitely does not provide for a great user experience but is one way to do it.

      Reply
  10. Sameer Roy says

    March 1, 2017 at 7:58 am

    Hello Chad,

    The video is freezing after some time when communication started in between web(Chrome) with android native webRTC.

    We are using Chrome 56.0.2924.87 and Android 6.0.1

    But in same devices (web to web) and (mobile to mobile) its working good.

    This issue is coming when the Chrome updates to 56 and it worked in the previous version of Chrome.

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Primary Sidebar

  • Sponsored. Become a webtcHacks sponsor

Email Subscription

Subscribe to our mailing list

* indicates required
webrtcHacksguides and information for WebRTC developers

Footer

SITE

  • Post List
  • About
  • Contact

Categories

  • Guide
  • Other
  • Reverse-Engineering
  • Review
  • Standards
  • Technology
  • Uncategorized

Tags

apple Blackbox Exploration Brief Chrome code computer vision DataChannel debug e2ee Edge extension getUserMedia Google Meet ICE insertable streams ios ip leakage janus jitsi MCU NAT opensource Opus ORTC Promo Q&A quic raspberry pi Safari SDP sfu simulcast standards TURN video vp8 VP9 w3c Walkthrough Web Audio webcodecs webrtc-internals webtransport WHIP wireshark

Follow

  • Twitter
  • YouTube
  • GitHub
  • RSS

webrtcHacks · copyright © 2025