LoginSignup
17
17

More than 5 years have passed since last update.

デスクトップブラウザでgetUserMediaを使用してカメラからの映像を表示しつつ、任意のタイミングで画像として保存する

Last updated at Posted at 2016-06-28

目的

デスクトップブラウザで、スマホのカメラアプリ的な動作を実装します。

PCに接続しているカメラの動画をvideoタグに映しつつ、
videoタグの表示領域をクリックするとその時の映像をPNGファイルとしてダウンロードします。

デモ

Chrome推奨 https://geekduck.github.io/getUserMedia/

demo.gif

機能

  1. MediaDevices.enumerateDevices APIを使用してカメラの情報を取得する(複数カメラ接続にも対応)
  2. MediaDevices.getUserMedia APIを使用してユーザが選んだデバイスIDのカメラ映像をvideoタグに表示する
  3. 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です。

MediaStreamConstraintsオブジェクト
{
  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のハマりポイント

  1. (少なくともChromeは)localhost接続か、https接続でしか使えない
    https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins

  2. 古いAPIが非推奨から廃止になった
    https://developers.google.com/web/updates/2015/07/mediastream-deprecations

17
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
17