ラズパイで居留守を極める

CYBIRDエンジニア Advent Calendar 2日目担当の @march_f です。
1日目は @ntrv さんによる「新規案件の設計について, 使用したサービスの紹介」でした。
私は普段恋愛ゲームのサーバー担当なので、インフラの構造や動きはとてもためになりました。
皆さんもぜひご覧ください！

# はじめに
CYBIRDはコロナ禍に入ってすぐに在宅勤務となったのですが、いざ在宅勤務になると宗教の勧誘や営業訪問が多く来る事に気付きました。
来るたびに確認に行くのも面倒ですし、居留守を使いたいので足音も出したくありません。が、よく通販を利用するためその宅配も逃したくありません。
そこで、玄関扉の覗き穴（ドアアイもしくはドアスコープと呼ぶそう）にカメラを設置して、作業部屋から誰が来たかを確認できるようにします。


# やること

* ドアスコープに内視鏡カメラ固定
* ラズパイにカメラを接続してRTSPサーバーをたてて配信する
* PC、スマホから視聴する

# 準備

今回は事前にラズパイへOSのインストールや設定をしている前提です。

## ハードウェア

* Raspberry Pi 4(OS、SSHなど設定済み)
* サンコー Android/PC両対応5.5mm径内視鏡ケーブル 2m 形状記憶タイプ MCADNEW2
https://www.amazon.co.jp/dp/B0758YWNFV

* 視聴用の環境(今回はWindows、iPhone)

- - -

* カメラはラズパイへ繋げておきます。
* 内視鏡カメラはドアスコープへ取り付けておきます。
![entrance.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138354/8df4110e-654b-6e16-b65a-a5abe7adc844.jpeg)


## ソフトウェア

* VLC Media Player（視聴用ソフト）<br>
https://www.videolan.org/index.ja.html <br>
スマホにもアプリがあります。

# カメラの設定

## 有効化＆確認

```
$ sudo raspi-config
```

1. 「3 Interface Options」→「P1 Camera」->「Yes」
設定したらカメラをラズパイに繋いで再起動

2. カメラのリストを表示

```
$ v4l2-ctl --list-devices
```

``/dev/video0`` が表示されていればOK

```
bcm2835-codec-decode (platform:bcm2835-codec):
        /dev/video10
        /dev/video11
        /dev/video12

bcm2835-isp (platform:bcm2835-isp):
        /dev/video13
        /dev/video14
        /dev/video15
        /dev/video16

USB2.0 PC CAMERA: USB2.0 PC CAM (usb-0000:01:00.0-1.3.4):
        /dev/video0
        /dev/video1
```

# RTSPサーバを立てる

## インストール
はじめに内視鏡カメラの対応フォーマットを見ます。

```
$ v4l2-ctl -d /dev/video0 --list-formats
```

```
ioctl: VIDIOC_ENUM_FMT
    Type: Video Capture

    [1]: 'YUYV' (YUYV 4:2:2)
```

今回使っている内視鏡カメラは YUYV しか表示されていません。
Webカメラを用いてRTSPサーバを立てる際は、v4l2rtspserver や VLC を使えば一瞬なのですが、今回のフォーマットだと初期で対応していないため使えません。(エンコーダーを追加するといけるようですが、いろいろ試して挫折...)
調べたところ、 gstreamer を使えばできるみたいなので、それを用いてRTSPサーバを構築できる gst-rtsp-server を使ってサーバをたてます。

 gstreamer は、映像と音声の圧縮・変換・復元したりできるフレームワークで、gst-rtsp-server はそれを用いてRTSPサーバを立てることができるライブラリです

> **Wikipediaより引用**
> 
> GStreamer（ジーストリーマー）は、フリー（ライセンスはLGPL）のマルチメディアフレームワーク。
>
> ビデオ編集ソフトやストリーミング、そしてメディアプレーヤーなどのようなマルチメディアアプリケーションのベースとなる機能を提供する。
> 

まず、必要なものを一式インストールします。

```
$ sudo apt install gstreamer1.0-tools
$ sudo apt install gstreamer1.0-plugins-good
$ sudo apt install gstreamer1.0-plugins-bad
$ sudo apt install gstreamer1.0-plugins-ugly
$ sudo apt install libglib2.0-dev
$ sudo apt install libgstreamer1.0-dev　
$ sudo apt install libgstreamer-plugins-base1.0-dev
```

インストールされたバージョンを確認します。

```
dpkg -l | grep gstreamer
```
次にダウンロードする `gst-rtsp-server` をこのバージョンと合わせる必要があります。
記事を書いている時点では 1.14.4 でした。
※バージョンが違う場合は 1.14.4 の部分を変えてください

```
$ wget https://gstreamer.freedesktop.org/src/gst-rtsp-server/gst-rtsp-server-1.14.4.tar.xz
$ tar -xf gst-rtsp-server-1.14.4.tar.xz
$ cd gst-rtsp-server-1.14.4
$ ./configure
$ make
$ sudo make install
```

## 起動

インストールしたフォルダに、test-launch というファイルがあり、これを実行すると簡単に rtspサーバ が立てられるのですが、
YUYV の場合はいろいろオプションをつけないといけないみたいで、当時ここがわからずずっと止まってました。

調べていくと、「YUYV camera + Raspberry Pi」 というめちゃくちゃピンポイントなコマンドを見つけました。
ありがとうございます🙏

https://gist.github.com/i-v-s/4ac5675cb588fb52983c2998631e6330

```
/home/pi/gst-rtsp-server-1.14.4/examples/test-launch "( v4l2src ! video/x-raw,format=YUY2,width=640,height=480 ! videoconvert ! video/x-raw,format=I420 ! videoconvert ! x264enc qp-min=18 speed-preset=superfast ! h264parse ! rtph264pay name=pay0 pt=96 config-interval=1 )"
```

実行すると `stream ready at rtsp://127.0.0.1:8554/test` という表示がでます。
この `127.0.0.1` をラズパイのIPアドレスにしたものが配信サーバーのアドレスになります。

<details><summary>コマンドの説明</summary><div>

なんでこのコマンドで動くのかあまり理解していないのですが、一応上記のコマンドに沿って `!` ごとにそれぞれの意味を書いておきます。(`!` はパイプラインです)
各要素はエレメントと呼ばれています。    

| コマンドNo. | エレメント | 意味 |
| --- | --- | --- |
| No.1 | v4l2src ! video/x-raw,format=YUY2,width=640,height=480 | ラズパイに繋がっているビデオの映像フォーマットを指定して取得。この場合は 620x480 のYUY2形式 |
| No.2 | videoconvert ! video/x-raw,format=I420 | No.1のビデオを I420 に変換する |
| No.3 | videoconvert ! x264enc qp-min=18 speed-preset=superfast | No.2 を h264 にエンコード  |
| No.4 | h264parse | No.3 をパーズ(解析)  |
| No.5 | rtph264pay name=pay0 pt=96 config-interval=1  | No.4 を RTPパケットにエンコード |

変換を多くしているのは、そのままだとその次の受け取り可能なフォーマットに対応していないからだと思われます。
    
例として、No.3 で指定している `x264enc` の受け取り可能なフォーマットには YUY2 がないため、受け取り可能な I420 に変換する必要があります。
    
エレメントの受け取り可能なフォーマットは以下で確認できます。

```
$ gst-inspect1.0 コマンド名
```

```
$ gst-inspect1.0 x264enc
```
</div></details>


## サービス化

毎回こんな長いの打てないのでサービス化します。

```
sudo vi /usr/lib/systemd/system/entrance-camera-rtsp.service
```

```/usr/lib/systemd/system/entrance-camera-rtsp.service
[Unit]
Description = RTSP server for entrance camera.

[Service]
ExecStart = /home/pi/gst-rtsp-server-1.14.4/examples/test-launch "( v4l2src ! video/x-raw,format=YUY2,width=640,height=480 ! videoconvert ! video/x-raw,format=I420 ! videoconvert ! x264enc qp-min=18 speed-preset=superfast ! h264parse ! rtph264pay name=pay0 pt=96 config-interval=1 )"
Restart = always
Type = simple

[Install]
WantedBy = multi-user.target
```

できてるか確認

```
sudo systemctl list-unit-files --type=service | grep entrance
```

以降は `sudo systemctl start entrance-camera-rtsp` で起動できます。

## 自動起動設定

```
sudo systemctl enable entrance-camera-rtsp
```

# 視聴

1. インストールした VLC Media Player を起動して
左上の「メディア」→「ネットワークストリームを開く」を押します。

2. ネットワークURLに入力して「再生」を押すと配信を見ることができます。

![vlc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138354/50a61f99-dc36-2d3b-327c-7635aa299db7.png)


接続するとカメラの映像が出ます。（出ない場合は３０秒ほど待つと出ます）
遅延は1秒～2秒ほどでした。

![ra.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138354/a0013874-7d64-6317-c46e-5ccfd58677c8.png)


この画像にはうつっていませんが、人を識別できるほどはっきりは見えました。

# さいごに

これでデスクから離れなくてよくなったが、ますます歩かなくなった。
明日のCYBIRDエンジニア Advent Calendar 2021 3日目は、 @kyorokyoro さんによる「アプリの通信回数を減らすためにやったこと」です。
通信回数は分野問わず重要なことなので、ぜひご覧ください！


ありがとうございました！

# 参考

* Raspberry PiでRTSPネットワークカメラを構築する方法
https://qiita.com/zono_0/items/43fc89876977738de402

* ラズパイ4とGStreamerでストリーミングサーバーを作ろう
https://qiita.com/suo-takefumi/items/aba3db7d639a8b1a8981

* How to make a Raspberry Pi an RTSP streamer and how to consume this?
https://gist.github.com/lemonlatte/799a43288b0e093f9c95ad83ae4962a3

* i-v-s/rtsp.sh YUYV camera + Raspberry Pi
https://gist.github.com/i-v-s/4ac5675cb588fb52983c2998631e6330

* GStreamer
https://ja.wikipedia.org/wiki/GStreamer

* GStreamer/gst-rtsp-server
https://github.com/GStreamer/gst-rtsp-server