Note: See February 2016 update here.
{“editor”, “chad“}
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:
- Pass – the resulting stream output has the same resolution of what was asked for in the mandatory constraints
- 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
- ConstraintNotSatisfiedError – this is a newer, more useful error that has been specified and is used in Chrome 39
- 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.
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:
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
Philipp Hancke says
“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!
Michael Graves says
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.
Chad Hart says
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.
James Morley says
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
Chad Hart says
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.
Matthias Doering says
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.
Chad Hart says
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.
Luong says
Thank you so much for this great post.
Miguel Casas Sanchez says
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
Chad Hart says
Thanks for sharing Miguel! This is very helpful – let me amend the post to include your comments.
Matt Bo says
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
Chad Hart says
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
Chad Hart says
I updated the scanner, added Edge, ran new scans, and made some new findings to this post here:
Avijit Sarkar says
How do i auto select the best available resolution?
Chad Hart says
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.
Sameer Roy says
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.