getUserMediaのConstraintsは、いまだブラウザーごとの実装に差異がありますが、W3CのMedia Capture and Streamsにconstraintsの値からカメラデバイスおよび解像度の選択において"fitness distance"というアルゴリズムが使用されると書かれています。
この"fitness distance"について説明したいと思います。
ただし、現在、このアルゴリズムをサポートしているのはFirefoxのみとなっています。
この"fitness distance"がどのようなアルゴリズムかというと、仕様にはアルゴリズムで使用する計算式が書かれています。
(actual == ideal) ? 0 : |actual - ideal|/max(|actual|,|ideal|)
actualにはカメラの解像度、idealにはconstraintsで設定した解像度が入ります。
解像度といっても、widthとheightの2つの値があります。ちょっと自信がないのですが、Firefoxのソースを見るとwidthとheightでそれぞれこの計算式で値を算出し、2つの値を足したものがそのカメラと解像度の組み合わせに対するConstraints設定とのdistance値としているようです。
接続されているカメラおよびカメラが対応している出力解像度分このdistance値を求め、distance値が最小となる組み合わせが選択されます。
例えば、constraintsを
{
video: {
width: 200,
height: 200
}
}
としたとき、解像度160x120のdistance値は
(160 == 200) ? 0 : Math.abs(160 - 200) / Math.max(160, 200) = 0.2
(120 == 200) ? 0 : Math.abs(120 - 200) / Math.max(120, 200) = 0.4
0.2 + 0.4 = 0.6
ということで0.6となります。
私が所有するカメラで検証してみました。
Logicool HD Webcam C615(以降Logicool) とノートPCに搭載されている BisonCam, NB Pro(以降Bison) というカメラです。
それぞれのカメラが提供している出力解像度は以下のようになっています。また既定デバイスはLogicool になっています。
Logicool(既定デバイス) | BisonCam |
---|---|
160x120 | 160x120 |
176x144 | 176x144 |
320x240 | 320x240 |
352x288 | 352x288 |
432x240 | - |
640x360 | 640x360 |
640x480 | 640x480 |
800x448 | - |
864x480 | - |
800x600 | - |
1024x576 | - |
960x720 | - |
1280x720 | 1280x720 |
- | 1280x1024 |
1600x896 | - |
1920x1080 | 1920x1080 |
ここで、Constraintsを以下のように設定してgetUsermedia()を実行してみます。
{
video:{
width: 300,
height: 300
}
}
すると、Logicoolで352x288の解像度が選択されてストリームが取得されました。
distanceの値を計算してみます。(小数点第3位四捨五入)
Logicool(既定デバイス) | BisonCam | distance値 |
---|---|---|
160x120 | 160x120 | 1.07 |
176x144 | 176x144 | 0.93 |
320x240 | 320x240 | 0.26 |
352x288 | 352x288 | ★0.19 |
432x240 | - | 0.51 |
640x360 | 640x360 | 0.7 |
640x480 | 640x480 | 0.91 |
800x448 | - | 0.96 |
864x480 | - | 1.03 |
800x600 | - | 1.13 |
1024x576 | - | 1.19 |
960x720 | - | 1.27 |
1280x720 | 1280x720 | 1.35 |
- | 1280x1024 | 1.47 |
1600x896 | - | 1.48 |
1920x1080 | 1920x1080 | 1.57 |
distance値が最小となったのは352x288の解像度で、この解像度は両デバイスともに対応していますが、既定デバイスがLogicoolですのでLogicoolを選択、ということで計算による選択と実際の動作が一致しました。
次にConstraintsを以下のようにして、getUserMedia()を実行してみます。
{
video:{
width: 1000,
height: 1000
}
}
すると、Bisonで1280x1024の解像度が選択されてストリームが取得されました。
distanceの値を計算してみます。
Logicool(既定デバイス) | BisonCam | distance値 |
---|---|---|
160x120 | 160x120 | 1.72 |
176x144 | 176x144 | 1.68 |
320x240 | 320x240 | 1.44 |
352x288 | 352x288 | 1.36 |
432x240 | - | 1.328 |
640x360 | 640x360 | 1 |
640x480 | 640x480 | 0.88 |
800x448 | - | 0.752 |
864x480 | - | 0.656 |
800x600 | - | 0.6 |
1024x576 | - | 0.4474375 |
960x720 | - | 0.32 |
1280x720 | 1280x720 | 0.5 |
- | 1280x1024 | ★0.24 |
1600x896 | - | 0.48 |
1920x1080 | 1920x1080 | 0.55 |
となり、解像度1280x1024がdistance値が最小となりますが、この解像度はBisonしかサポートしていませんので、Bisonで1280x1024を選択ということでこれも実際の動作と一致しました。
このように、デバイスを指定していない場合、既定のデバイスとは違うデバイスが選択される場合があることに注意しておいたほうがいいでしょう。