ブラウザから取得したカメラの映像を、加工してキャプチャーする方法。

# 目的
* `getUserMedia()`で取得した映像を加工する。
* 加工した映像をキャプチャーする。

# 概要
* canvasを使って映像を加工する。
* なんの役に立つかは僕の頭では見いだせなかったけど、技術として面白くて好き。

# 開発環境
* OS: macOS Mojave 10.14.4
* ブラウザ: Google Chrome 73.0.3683.103
* エディター: Visual Studio Code 1.33.0
* ローカルサーバー: [Live Server](https://github.com/ritwickdey/vscode-live-server)（VSCode拡張機能）

# 対応ブラウザ
## getUserMedia
<img width="1176" alt="スクリーンショット 2019-04-23 22.01.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396925/b691589d-f5cc-fb58-42d4-16880e485425.png">
参照:[getUserMedia/Stream API](https://caniuse.com/#search=getusermedia)

## canvas
<img width="1175" alt="スクリーンショット 2019-04-23 22.04.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396925/fd01973a-b24c-8d55-2ec5-2afa90229408.png">
参照:[Canvas (basic support)](https://caniuse.com/#search=canvas)


# ゴール
![Kapture 2019-04-23 at 21.56.28 (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396925/29a3d2f7-979e-9131-d338-c7e75d212ed7.gif)

# ソース
## javascript
```javascript:js/index.js
/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */

'use strict';

const snapshotButton = document.querySelector('button');
const filterSelect = document.querySelector('select#filter');

const video = window.video = document.querySelector('video');
const canvas = window.canvas = document.querySelector('canvas');
canvas.width = 480;
canvas.height = 360;

snapshotButton.onclick = function () {
  canvas.width = video.videoWidth;
  canvas.height = video.videoHeight;
  canvas.className = filterSelect.value;
  canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
};

filterSelect.onchange = function () {
  video.className = filterSelect.value;
};

const constraints = {
  audio: false,
  video: true
};

function handleSuccess(stream) {
  window.stream = stream;
  video.srcObject = stream;
}

function handleError(error) {
  console.log('navigator.MediaDevices.getUserMedia error: ', error.message, error.name);
}

navigator.mediaDevices.getUserMedia(constraints).then(handleSuccess).catch(handleError);
```
## html
```html/index.html
<!DOCTYPE html>
<!--
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
-->
<html lang="jp">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>getUserMedia() with canvas</title>
<link rel="stylesheet" href="style.css">
</head>
<body>

  <h1>webRTC - getUserMedia with canvas</h1>
  <video playsinline autoplay></video>
  <div>
    <label for="filter">フィルター: </label>
    <select id="filter">
      <option value="none">なし</option>
      <option value="blur">Blur</option>
      <option value="grayscale">Grayscale</option>
      <option value="invert">Invert</option>
      <option value="sepia">Sepia</option>
    </select>
    <button>撮影する</button>
  </div>
  <canvas></canvas>

<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src="index.js" async></script>
</body>
</html>

```
## css
```css/style.css
.none {
    -webkit-filter: none;
    filter: none;
}
.blur {
    -webkit-filter: blur(3px);
    filter: blur(3px);
}
.grayscale {
    -webkit-filter: grayscale(1);
    filter: grayscale(1);
}
.invert {
    -webkit-filter: invert(1);
    filter: invert(1);
}
.sepia {
    -webkit-filter: sepia(1);
    filter: sepia(1);
}
button#snapshot {
    margin: 0 10px 25px 0;
    width: 110px;
}
video {
    object-fit: cover;
}
```

## 説明
```javascript/index.js
const snapshotButton = document.querySelector('button');
const filterSelect = document.querySelector('select#filter');

const video = window.video = document.querySelector('video');
const canvas = window.canvas = document.querySelector('canvas');
```
* 各種要素を取得する。

```javascript/index.js
snapshotButton.onclick = function () {
  canvas.width = video.videoWidth;
  canvas.height = video.videoHeight;
  canvas.className = filterSelect.value;
  canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);

  filterSelect.onchange = function () {
    video.className = filterSelect.value;
  };
};
```
* 撮影ボタンが押されたら、まずビデオのサイズを取得する。
* その後、フィルターの値をcanvasにわたす。
* canvasに描画するために`getContext()`を呼び出す。
* canvas上に画像を表示させるために`drawImage()`を呼び出す。

```javascript/index.js
const constraints = {
  audio: false,
  video: true
};

function handleSuccess(stream) {
  window.stream = stream;
  video.srcObject = stream;
}

function handleError(error) {
  console.log('navigator.MediaDevices.getUserMedia error: ', error.message, error.name);
}

navigator.mediaDevices.getUserMedia(constraints).then(handleSuccess).catch(handleError);
```
* `getUserMedia()`を実行して、ブラウザからデバイスのカメラ映像を取得する。
* `getUserMedia()`が成功したら、取得したmediaStreamをvideo要素のsrcにわたす。
* 失敗したらブラウザのコンソールにエラーを表示する。


# ひとこと
* 何に使えるかわからないけど、見た目が変わるのは楽しい。

# 参考文献
[Real time communication with WebRTC](https://codelabs.developers.google.com/codelabs/webrtc-web/#3)