配偶者の暴言２４時間監視・記録システム（ffmpeg, ラズパイ）

* 赤ちゃんの見守り・成長記録、
* 不審者の監視・記録

などにも使えます。ラズパイ上でffmpegを使って録画し、録画ファイルをウェブから見られるようにします。ラズパイではなくても常時稼働のLinux＆systemdならだいたい同じようにできますし、ウェブカメラへのアクセス方法を変えればWindows・Macでもほぼ同様にできます。ラズパイのSDカードだとおそらく容量が不足するため、USBでHDDまたはSSDを繋いでそこに録画していくのがよいと思われます。

# 実行例

![Screenshot from 2021-05-06 16-21-24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259309/ee27f01b-2f32-38e5-7c1d-c36af19ed16b.png)

ウェブブラウザからファイルをクリックすると

![Screenshot from 2021-05-06 16-22-29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259309/66345e41-1886-a088-499c-3333de1455f6.png)

# 手順
以下すべての手順を `sudo bash` などしてrootのプロンプトが出ている状態で行います。

## 使用したソフトウェアのバージョン

```shell-session
# uname -a
Linux raspi4b-router 5.10.0-6-rt-arm64 #1 SMP PREEMPT_RT Debian 5.10.28-1 (2021-04-09) aarch64 GNU/Linux
# systemctl --version
systemd 247 (247.3-5)
+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +ZSTD +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=unified
# ffmpeg -version
ffmpeg version 4.3.2-0+deb11u1 Copyright (c) 2000-2021 the FFmpeg developers
built with gcc 10 (Debian 10.2.1-6)
configuration: --prefix=/usr --extra-version=0+deb11u1 --toolchain=hardened --libdir=/usr/lib/aarch64-linux-gnu --incdir=/usr/include/aarch64-linux-gnu --arch=arm64 --enable-gpl --disable-stripping --enable-avresample --disable-filter=resample --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libdav1d --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librabbitmq --enable-librsvg --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-pocketsphinx --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
libavutil      56. 51.100 / 56. 51.100
libavcodec     58. 91.100 / 58. 91.100
libavformat    58. 45.100 / 58. 45.100
libavdevice    58. 10.100 / 58. 10.100
libavfilter     7. 85.100 /  7. 85.100
libavresample   4.  0.  0 /  4.  0.  0
libswscale      5.  7.100 /  5.  7.100
libswresample   3.  7.100 /  3.  7.100
libpostproc    55.  7.100 / 55.  7.100
```

## ウェブカメラ撮影の準備・確認

1. `apt-get install v4l-utils`
1. `v4l2-ctl -d /dev/video0 --list-formats-ext` で `/dev/video0` に繋がるウェブカメラが対応する解像度(resolution)とフレームレート(framerate)を確認する

## 録音するデバイスの準備・確認
1. `pulseaudio` が録音デバイスを管理している場合は以下の手順ではダメなので、`pulseaudio` をアンインストールします。
1. `arecord --list-device` で録音するデバイスの番号を確認します。以下の例だと `hw:1,0` を後で `ffmpeg` に与えます。

```shell-session
# arecord --list-device
**** List of CAPTURE Hardware Devices ****
card 1: Webcam [ELECOM 2MP Webcam], device 0: USB Audio [USB Audio]
  Subdevices: 0/1
  Subdevice #0: subdevice #0
```

## 動画を置いて配信するためのウェブサーバーの準備
`apache2` でも `nginx` でも [lighttpd](https://ja.wikipedia.org/wiki/Lighttpd) でもなんでもいいので、次のシェルスクリプトの `$dir` に設定するディレクトリに置かれたファイルが一覧として表示されるように設定します。

## シェルスクリプト
以下のシェルスクリプトの冒頭の変数を適切に設定して `/root/record.sh` として置きます。

```shell:/root/record.sh
#!/bin/sh
#↓録画を置くディレクトリ
dir=/var/www/html/video
#↓録音元（マイク）
micdevice=hw:1,0
#↓録画元
videodevice=/dev/video0
#↓録画解像度
resolution=352x288
#↓録画のFPS
framerate=6
#↓フォントのファイル
fontfile=/usr/share/fonts/truetype/unifont/unifont.ttf
#↓１ファイルあたりの録画時間（秒）
duration=3600

exec /usr/bin/ffmpeg -xerror -y -loglevel level+warning \
     -filter_complex "aresample=async=1000;drawtext=fontfile=${fontfile}:box=1:boxcolor=white:fontsize=32:text='%{localtime\:%F_%T}'" \
     -f alsa -thread_queue_size 8192 -i ${micdevice} \
     -f v4l2 -vsync cfr -thread_queue_size 8192 -s ${resolution} \
     -framerate ${framerate} -i ${videodevice} \
     -f mp4 -tune zerolatency -preset veryfast -t ${duration} -pix_fmt yuv420p \
     -movflags frag_keyframe+empty_moov+default_base_moof -frag_size 1000000 \
     ${dir}/record-`date +%F_%R`.mp4
```

## systemdによる自動起動
以下のファイルを `/etc/systemd/system/record.service` という名前で置いた後に、`systemctl enable --now record` とすると起動され、再起動後も自動起動されます。

```config:/etc/systemd/system/record.service
[Service]
Type=exec
CPUSchedulingPolicy=rr
CPUSchedulingPriority=2
Restart=always
ExecStart=/bin/sh /root/record.sh

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

録画がコマ落ちすることを避けるために、上記では`ffmpeg`を[リアルタイム優先度](https://qiita.com/akira2768922/items/e1b146e0952dd3598ce1)で実行させています。

## 古くなった録画の自動消去

以下の２つのファイルを置いたあとに `systemctl enable --now deleterecord.timer` すると録画から１０日以上経過した古いファイルが自動的に消されるようになります。

```config:/etc/systemd/system/deleterecord.service
[Service]
Type=exec
Nice=5
#↓以下のディレクトリを録画保存ディレクトリに直す
ExecStart=/usr/bin/find /var/www/html/video -mmin +864000 -ls -delete
```

```config:/etc/systemd/system/deleterecord.timer
[Timer]
OnCalendar=*-*-* *:05:00
Persistent=false

[Install]
WantedBy=timers.target
```


# ffmpegのオプション解説
ffmpeg は入出力両方に関連するオプションと、個々の入力または出力に関連するオプションに大別されます。

## 入出力両方に関連するオプション
* `-xerror` エラーが生じたら終了する
* `-y` 記録するファイルが既に存在する場合に上書きする
* ` -loglevel level+warning` 標準エラー出力に表示するログの詳しさの調節
* `-filter_complex "aresample=async=1000;drawtext=fontfile=${fontfile}:box=1:boxcolor=white:fontsize=32:text='%{localtime\:%F_%T}'"` 映像と音を同期させるように音をリサンプリングするのと、映像に時刻を上書きする

## 録音元に関連するオプション
* `-f alsa` 録音の形式としてALSAを選択する。もしPulseAudioから録音する場合 [-f pulse](https://trac.ffmpeg.org/wiki/Capture/PulseAudio) に換える
* `-thread_queue_size 8192` おまじない
* `-i ${micdevice}` 録音元の指定

## 録画元に関連するオプション
* `-f v4l2` 録画元の形式の指定
* `-vsync cfr` 指定したフレームレートで実際のコマがウェブカメラから来ないときに、コマの削除または複製を行い、フレームレートが指定した値になるようにする
* `-thread_queue_size 8192` おまじない
* `-s ${resolution}` 録画解像度の指定
* `-framerate ${framerate}` 毎秒あたりのコマ数の指定
* `-i ${videodevice}` 録画元の指定

## 録画映像書き出しに関連するオプション
* `-f mp4` MPEG4形式を指定
* `-tune zerolatency` 指定するといいらしい
* `-preset veryfast` [圧縮率と圧縮に掛かる時間のトレードオフが最も優れるらしい](https://qiita.com/m-sakano/items/63930830faff72a256ac)
* `-pix_fmt yuv420p` [MacやWindows 7で再生するときに付けるといいらしい](https://qiita.com/mriho/items/a16b3c618c378efeb58f)
* `-movflags frag_keyframe+empty_moov+default_base_moof` [録画途中でも再生できるように必要な情報を録画ファイル内で分散させる](https://developer.mozilla.org/ja/docs/Web/API/Media_Source_Extensions_API/Transcoding_assets_for_MSE)
* `-frag_size 1000000` 上記情報をおおよそ1000000バイトごとに録画ファイルに書き込む

# 今後の課題
* ディープラーニング異常検知による暴言の自動的な抽出
* 録画ファイル内のおなら回数の自動数え上げ