obnizOSを使ってm5stackをサブディスプレイ化してみた

m5stack.jsを出したので色々遊んでみました。
やっぱりちっちゃいディスプレイがあるので、そこで遊びたいですよね。
画像表示させたいですよね。TVとかyoutubeを流したいですよね。<font color="red">**サブディスプレイにしたいですよね**</font>

というわけでやってみました。

# つくったもの
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/m5stack?src=hash&amp;ref_src=twsrc%5Etfw">#m5stack</a> をサブディスプレイとして採用しました　<a href="https://twitter.com/hashtag/obnizOS?src=hash&amp;ref_src=twsrc%5Etfw">#obnizOS</a> <a href="https://t.co/T9NbuqUAUI">pic.twitter.com/T9NbuqUAUI</a></p>&mdash; kido@IoTエンジニア (@9wick) <a href="https://twitter.com/9wick/status/1164831075283038208?ref_src=twsrc%5Etfw">2019年8月23日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

だいたい60行ぐらいのプログラムです。 **お手軽感満載です**
かわりにソースコード外で色々頑張ってるところがあります。

# しくみ

サブディスプレイのキャプチャを撮ってm5stackで表示しています。
色々小ネタはありますが、基本的にはそれだけです。

これを実現するのに、chrome(HTML)と[obnizOS](https://obniz.io)を使っています。

<img width="911" alt="スクリーンショット 2019-08-24 10.36.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227015/49d5bb36-3a0a-bd3c-c994-0ba471349ca8.png">


サブディスプレイの画像取得にはchromeの`getDisplayMedia`をつかっています。
最近のブラウザは便利で、ディスプレイのキャプチャまで取れてしまうんですね・・・恐ろしい時代・・・。

流れとしてはこれだけです。
1. 仮想サブディスプレイをつくる（今回未実施）
2. ディスプレイの内容をHTMLで取得する
3. 取得した画像をobnizOSをつかってM5Stackへ転送する


**仮想サブディスプレイをつくる（今回未実施）**のところだけ、よくわからなかったのでリアルディスプレイをつないでごまかしました。世の中には仮想ディスプレイデバイスとかあるっぽいので、それを使えばできるかと思います。（でもホントはソフトでやりたい）

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">これすげー！探してたけどほんとにあるとは…！ソフトだけだと難しいのかな？<br><br>HDMI virtual display  <a href="https://t.co/iiRKo9jQAU">https://t.co/iiRKo9jQAU</a></p>&mdash; kido@IoTエンジニア (@9wick) <a href="https://twitter.com/9wick/status/1164922991236435968?ref_src=twsrc%5Etfw">2019年8月23日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# 作り方

まずはm5stackにobnizOSをインストールします。
こちらの記事とか、公式サイトに手順が書かれています。

- [obnizOSをM5Stack(M5StickC)にインストールする手順](https://qiita.com/iizuka2019/items/4736796f4d07b82c677e)
- [公式サイトのドキュメント](https://obniz.io/ja/doc/obnizos/os_quickstart)


obnizOSをインストールしたら、htmlアプリを作るだけです。
localhostか、もしくはSSL対応のところにHTMLをホスティングして作ります。
obnizの開発者コンソール内に作るのが楽です。


プログラムとしては、

1. スクリーンショットを撮ってvideoタグに描画する
1. videoの内容をcanvasに描画する
2. canvasの内容をm5stackに描画する

だけです。


### プログラムの下準備


HTML上で、canvasとvideoタグを宣言しておきます

```html
<video controls id="v" width="480px" height="270px" autoplay></video>
<canvas id="c" width="320px" height="260px"></canvas>
```

JavaScript側でも使うので、変数を作っておきます

```javascript
  let canvas = document.getElementById("c");
  var video = document.getElementById("v");
```



### スクリーンショットを撮ってvideoタグに描画する


まずはvideoタグにスクリーンショットが入るようにします。


```javascript
  navigator.mediaDevices.getDisplayMedia({audio: false, video: true}).then(stream => {
    video.srcObject = stream;
  })
```

これを実行するとchrome上でどの画面を描画するか？のダイアログが出てきて、画面を選ぶことができます。

<img width="1265" alt="スクリーンショット 2019-08-24 10.35.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227015/0cda9548-523c-29bf-2a21-a7c1a3101423.png">

面白いのがchromeのタブ(バックグラウンド実行も可)を選ぶこともできて、これはこれで色々できちゃうんですね。

ここで画面を選ぶと、その内容がvideoタグに入るようになります。

### videoの内容をcanvasに描画する

canvasのdrawImageでそのままかけますので、canvasに描画します。

```javascript
var ctx1 = canvas.getContext('2d');
ctx1.drawImage(video, 0, 0, 320, 240);
```

このとき、矩形抽出とかすれば特定領域だけm5stackに表示とかもできます。
2行でできてシンプルですね

###  canvasの内容をm5stackに描画する

ライブラリを使うので、scriptタグで読み込んでおきましょう

```html
  <script src="https://unpkg.com/obniz@2.2.0/obniz.js"></script>
  <script src="https://unpkg.com/m5stackjs/m5stack.js"></script>
```


obnizOSが入ったm5stacktと接続します。
OBNIZ_ID_HEREのところはm5stackにいれたobnizOSの番号を入れてください。

```javascript
  let m5 = new M5Stack('OBNIZ_ID_HERE');

  m5.onconnect = async function () {
    await m5.m5display.onWait();
    ...
  };
```

m5stackに描画するには、canvasをdrawするだけです

```javascript
      m5.m5display.draw(ctx1);
```

これで出来上がりです！

### プログラム全体

プログラムとしてはこちらです！
だいたい60行ぐらいかな。

<details><summary>プログラムすべてを表示</summary><div>

```html

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>youtube stack</title>
  <script src="https://obniz.io/js/jquery-3.2.1.min.js"></script>
  <script src="https://unpkg.com/obniz@2.2.0/obniz.js"></script>
  <script src="https://unpkg.com/m5stackjs/m5stack.js"></script>
</head>
<body>

<video controls id="v" width="480px" height="270px" autoplay></video>
<canvas id="c" width="320px" height="260px"></canvas>

<script type="text/javascript">
  let canvas = document.getElementById("c");
  var video = document.getElementById("v");

  let m5 = new M5Stack('OBNIZ_ID_HERE');

  m5.onconnect = async function () {
    await m5.m5display.onWait();
    var ctx1 = canvas.getContext('2d');

    while (1) {
      ctx1.drawImage(video, 0, 0, 320, 240);
      m5.m5display.draw(ctx1);

      //描画サイクルが早すぎるとエラーになることがあるので調整
      await new Promise(resolve => {
        setTimeout(resolve, 100)
      });
      await m5.pingWait();
    }
  };

  navigator.mediaDevices.getDisplayMedia({audio: false, video: true}).then(stream => {
    video.srcObject = stream;
  })

</script>
</body>
</html>
```
</details></div>


サブディスプレイとして活用して遊びましょう！

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/m5stack?src=hash&amp;ref_src=twsrc%5Etfw">#m5stack</a> をサブディスプレイとして採用しました　<a href="https://twitter.com/hashtag/obnizOS?src=hash&amp;ref_src=twsrc%5Etfw">#obnizOS</a> <a href="https://t.co/T9NbuqUAUI">pic.twitter.com/T9NbuqUAUI</a></p>&mdash; kido@IoTエンジニア (@9wick) <a href="https://twitter.com/9wick/status/1164831075283038208?ref_src=twsrc%5Etfw">2019年8月23日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 応用

chromeタブを描画範囲にしてyoutubeを流してみました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/m5stack?src=hash&amp;ref_src=twsrc%5Etfw">#m5stack</a> の youtube流し、速度早くなった！ <a href="https://twitter.com/hashtag/obnizOS?src=hash&amp;ref_src=twsrc%5Etfw">#obnizOS</a> <a href="https://t.co/K6XQinc4ar">pic.twitter.com/K6XQinc4ar</a></p>&mdash; kido@IoTエンジニア (@9wick) <a href="https://twitter.com/9wick/status/1164827380466114560?ref_src=twsrc%5Etfw">2019年8月23日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>