目的
デスクトップブラウザで、スマホのカメラアプリ的な動作を実装します。
PCに接続しているカメラの動画をvideoタグに映しつつ、
videoタグの表示領域をクリックするとその時の映像をPNGファイルとしてダウンロードします。
デモ
Chrome推奨 https://geekduck.github.io/getUserMedia/
機能
- MediaDevices.enumerateDevices APIを使用してカメラの情報を取得する(複数カメラ接続にも対応)
- MediaDevices.getUserMedia APIを使用してユーザが選んだデバイスIDのカメラ映像をvideoタグに表示する
- videoタグから画像を生成してダウンロードさせる
MediaDevices.enumerateDevices APIを使用してカメラの情報を取得する(複数カメラ接続にも対応)
// 接続されているカメラとマイクのMediaStreamオブジェクトを取得する
navigator.mediaDevices.enumerateDevices().then(function(sourcesInfo) {
// 取得できたカメラとマイクを含むデバイスからカメラだけをフィルターする
var videoSroucesArray = sourcesInfo.filter(function(elem) {
return elem.kind == 'videoinput';
});
render(videoSroucesArray);
});
/**
* カメラを選択するセレクトボックスを組み立てる
*/
function render(videoSroucesArray) {
var $selectBox = document.querySelector('#select')
videoSroucesArray.forEach(function(source, idx) {
var label = source.label !== "" ? source.label : ("カメラ" + idx);
$selectBox.insertAdjacentHTML("beforeend", "<option value='" + source.deviceId + "'>" + label + "</option>");
});
return this;
}
MediaDevices.enumerateDevices APIを使用することで、
MediaDeviceInfoオブジェクトの配列が取得できます。
このMediaDeviceInfoオブジェクトは接続されているデバイスの種類(カメラorマイク)やデバイスID、ラベル名などの情報を持ったオブジェクトです。
具体的には以下のようなプロパティ名を持ったオブジェクトです。
{
deviceId: "61f2432c64f7d3c9ebb1be1c754bdaf0d555df7b83a4a7d2c68aec92f15829c5"
groupId: "3104884528"
kind: "audioinput"
label: ""
}
{
deviceId: "3052d5f08d08eb5a356080db8fce7efb4602cd1774274f1eac4d32353ea98f9b"
groupId: ""
kind: "videoinput"
label: "FaceTime HD カメラ"
}
実際にカメラと接続するgetUserMedia APIに必要な情報はデバイスIDだけです。
取得したデバイスIDとラベル名を使用してセレクトボックスを組み立てています。
MediaDevices.getUserMedia APIを使用してユーザが選んだデバイスIDのカメラ映像をvideoタグに表示する
var currentStream;
/**
* カメラの再生を開始する
*/
function start(e) {
// 既にカメラと接続していたら停止
if (currentStream) {
currentStream.getVideoTracks().forEach(function(devise) {
devise.stop();
});
currentStream = null;
}
if (e.target.value === "") {
return;
}
var constraints = {
video: {
optional: [{
sourceId: e.target.value
}]
}
};
// Video と Audioのキャプチャを開始
navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
currentStream = stream; // カメラを切り替えた時に停止するため格納
var $video = document.querySelector('#video');
$video.src = window.URL.createObjectURL(stream);
$video.play(); // firefox用
}, function() {
console.log("error:" + arguments);
})
}
var selectBox = document.querySelector('#select');
selectBox.addEventListener('change', start, false);
セレクトボックスで選ばれたデバイスIDを引数にMediaDevices.getUserMedia APIを実行するとカメラからの映像を取得できます。
第一引数はMediaStreamConstraintsオブジェクトと呼ばれていて以下のような形式で指定します。
sourceIdに指定しているのはMediaDevices.enumerateDevicesで取得したデバイスIDです。
{
video: {
width: 1280,
height: 720,
optional: [{
sourceId: "3052d5f08d08eb5a356080db8fce7efb4602cd1774274f1eac4d32353ea98f9b"
}]
},
audio: true
}
videoタグから画像を生成してダウンロードさせる
function download() {
var cEle = document.createElement('canvas');
var cCtx = cEle.getContext('2d');
var vEle = document.querySelector('#video');
cEle.width = vEle.videoWidth; // canvasの幅と高さを、動画の幅と高さに合わせる
cEle.height = vEle.videoHeight;
cCtx.drawImage(vEle, 0, 0); // canvasに関数実行時の動画のフレームを描画
var aTag = document.createElement('a');
aTag.setAttribute('href', cEle.toDataURL());
aTag.setAttribute('download', "video.png");
aTag.click(); // Firefoxでは動かない
}
var video = document.querySelector('#video');
video.addEventListener('click', download, false);
canvas要素のtoDataURLメソッドを使って、videoタグの映像を切り出してBase64エンコード文字列に変換します。
その文字列をaタグのhrefに指定してダウンロードさせています。
getUserMediaのハマりポイント
(少なくともChromeは)localhost接続か、https接続でしか使えない
https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins古いAPIが非推奨から廃止になった
https://developers.google.com/web/updates/2015/07/mediastream-deprecations