はじめに
株式会社マイスター・ギルド新規事業部のウサギーです。
弊社新規事業部では、新規サービスの立ち上げを目指して
日々、アイディアの検証やプロトタイプの作成を行っています。
今回は、スマートフォン向けのWebアプリネタです。
カメラの利用
ブラウザでデバイスのカメラを利用する場合、私はこういうコードを書いています。
<video id="video" autoplay muted playsinline></video>
const video = document.getElementById('video')
navigator.mediaDevices.getUserMedia({
video:{width:300 height:300},
audio:false,
}).then(stream => {
video.srcObject = stream;
video.play()
}).catch(e => {
console.log(e)
})
スマホで表示するとインカメラが利用されます。
例えば、撮影機能のあるカメラアプリを作る場合なんかであれば
アウトカメラも使いたい…
ということで、今回は切り替えを実装しようと思います。
インカメラの場合
navigator.mediaDevices.getUserMedia({
video:{width:300 height:300
+ facingMode: "user"},
audio:false,
}
アウトカメラの場合
navigator.mediaDevices.getUserMedia({
video:{width:300 height:300
+ facingMode: { exact: "environment" }},
audio:false,
}
切り替えボタンを作る
<div>
<button id="btn">カメラ切り替え</button>
<span id="camera-facing"></span>
</div>
let cameraFacingIsUser = true; // デフォルトはインカメラ
let facingText = document.getElementById('camera-facing');
facingText.innerText = "インカメラ";
document.getElementById('btn').onclick = () => {
if(cameraFacingIsUser){
facingText.innerText = "アウトカメラ";
cameraFacingIsUser = false;
}else{
facingText.innerText = "インカメラ";
cameraFacingIsUser = true;
}
}
押したら文言が切り替わります。
この切り替え部分で、faceMogdingも書き替えるようにします。
let localStream;
const constraints = {
video: {
width: 640,
height: 480,
facingMode: 'user' // デフォルトはインカメラ
},
audio: false
};
const getStream = (isUser) => {
// 直前のストリームを停止する
if (localStream !== undefined) {
localStream.getVideoTracks().forEach((camera) => {
camera.stop();
console.log("camera stop");
});
}
// 再読み込み
constraints.video.facingMode = isUser ? 'user' : { exact: 'environment' }
navigator.mediaDevices.getUserMedia(constraints)
.then(stream => {
localStream = stream;
video.srcObject = stream;
video.play();
}).catch(e => {
console.log(e)
})
}
getStream(true);
これで切り替えできます。
躓いたところ
(1)アウトカメラの指定
アウトカメラを指定するとき、facingModeにはオブジェクト{ exact: 'environment' }を指定しないといけないのですが、
インカメラ時の指定にひきずられてうっかり文字列として
constraints.video.facingMode = "{ exact: 'environment' }";
と指定してしまっていてアウトカメラが利用できずに???となっていました。
初歩的なミスではありますが、お気を付けください!
(2)PCの場合
インカメラ、アウトカメラの指定はスマートフォンデバイスのように元々固有のカメラセンサを2つ持っているもの向けのようです。
私の環境では、ノートPCについているインカメラは’user’で
別途USBでつないでいたWebカメラは{ exact: 'environment' }ではありませんでした。
PC向けにカメラを切り替えるコードを用意する場合は、
navigator.mediaDevices.enumerateDevices()
.then(function(devices) {
devices.forEach(function(device) {
if(device.kind === "videoinput"){
console.log(device.kind + ": " + device.label + device.devideid);
// ここでdeviceのリストを作って利用するなど
}
});
})
.catch(function(err) {
console.log(err.name + ": " + err.message);
});
のようにdevice.kindがvideoinputのものを取得し、deviceidを指定して切り替えてあげるとよいかもしれません。
おわりに
スマートフォンデバイスでのカメラの切り替え方法を学びました!
カメラを利用したWebアプリづくりに活かせたらいいな~と思います
おまけ
作ったコードです
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>OutCameraTest</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/destyle.css@1.0.15/destyle.css"/>
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>
<body>
<div class="content_wrapper">
<h1>WEBカメラの映像を表示</h1>
<div class="video-container">
<video id="video" autoplay muted playsinline></video>
</div>
<div>
<button id="btn">カメラ切り替え</button>
<span id="camera-facing"></span>
</div>
</div>
<script src="./script.js" defer></script>
</body>
</html>
main.js
let localStream;
const constraints = {
video: {
width: 640,
height: 480,
facingMode: 'user' // デフォルトはインカメラ
},
audio: false
};
const getStream = (isUser) => {
// 直前のストリームを停止する
if (localStream !== undefined) {
localStream.getVideoTracks().forEach((camera) => {
camera.stop();
console.log("camera stop");
});
}
// 再読み込み
constraints.video.facingMode = isUser ? 'user' : { exact: 'environment' }
navigator.mediaDevices.getUserMedia(constraints)
.then(stream => {
localStream = stream;
video.srcObject = stream;
video.play();
}).catch(e => {
console.log(e);
})
}
const video = document.getElementById('video');
getStream(true);
let cameraFacingIsUser = true;
let facingText = document.getElementById('camera-facing');
facingText.innerText = "インカメラ";
document.getElementById('btn').onclick = () => {
if (cameraFacingIsUser) {
facingText.innerText = "アウトカメラ";
cameraFacingIsUser = false;
getStream(false);
} else {
facingText.innerText = "インカメラ";
cameraFacingIsUser = true;
getStream(true);
}
}
style.css
.content_wrapper{
position: relative;
}
.video-container{
position: absolute;
width: 100vw;
height: 100vh;
top: 0px;
left: 0px;
}
#video {
position: absolute;
background: #FFF;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
object-fit: cover;
z-index: 900;
}
#btn {
position: absolute;
bottom: 10px;
left: 10px;
z-index: 1000;
background-color: #eee;
border: 1px solid #000;
padding: 3px 5px;
border-radius: 7px;
}
#camera-facing{
position: absolute;
bottom: 40px;
left: 10px;
z-index: 1001;
}