LinuxでUSBカメラ映像をストリーミングかつ録画する
USBカメラの映像をネットワーク越しにストリーミング視聴できるようにしつつ、24時間録画する方法についてメモ。GStreamerを使用した。
ハードウェア
- Raspberry Pi 3
- Logitech C920(H264エンコーダ付き)
ストリーミング方法
検討したプロトコルが以下の4つ。
- HLS
- DASH
- RTMP
- RTSP
前者2つはHTTPベースなので扱いが楽。ただしレイテンシが数十秒レベルとだいぶ長め。
RTMPはFlashでよく使われていたプロトコル。まぁ新しく使う理由はあまりない。GStreamerにデフォルトでプラグインがあるので、別のサーバに映像を送るのに使えるかもしれない。例えば、NGINXのRTMPモジュールで受けて、HLSで再送するなど。レイテンシ低い。
RTSPはよくIPカメラとかで使われているイメージ。レイテンシ低くて良い。ただしGStreamerから使うのはすこし面倒。
今回はHLSを使うことにした。GStreamerにデフォルトでプラグインがあるので楽だったので。
録画先
NASをCIFSマウントしてそこにMP4ファイルを書き込むことにした。SDカードに直接書き込むのは寿命の観点から避ける。
同様に、HLSの書き込み先もSDカードは避け、メモリ上にした。
mount -t tmpfs -o size=100M /mnt/tmp
USBカメラの接続
Raspberry pi上にはUbuntu Serverをインストールした。ドライバは標準で含まれているので、カメラを接続するだけで認識された。
以下はカメラの確認のための手順。
- dmesgコマンドでカメラが認識されたことの確認
- lsusbコマンドで同様の確認
- ls /dev/video*でデバイスファイルが存在することの確認
- ファイルパーミッションの設定。今回は自ユーザをvideoグループに追加した。audioグループにも入れておくと良い。
- v4l2-ctl --allでカメラ情報の確認。APTでv4l2-toolsをインストールすること。
- v4l2-ctl --info --list-formatsで対応フォーマットの確認。
なお、C920は2020年頃からH264のサポートを辞めたそうなので注意。もしH264がサポートされていない場合、Raspberry pi上でのエンコードが必要となる。どのくらいの速度がでるのかは試していないので不明。
次にマイクの確認
sudo apt install alsa-utils sudo arecord -l
GStreamerのセットアップ
基本的にすべてAPTでインストールできる。
sudo apt install gstreamer1.0-tools gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-alsa
使ったコマンドは
gst-launch-1.0 -e v4l2src device=/dev/video0 ! video/x-h264,framerate=15/1 ! tee name=v ! queue ! h264parse ! mux.video_0 alsasrc device="default:CARD=C920" ! voaacenc ! aacparse ! queue ! tee name=a ! mux.audio_0 mp4mux name=mux ! filesink location=/mnt/videos/`date +%y%m%d%H%M`.mp4 buffer-size=1000000 v. ! queue ! h264parse ! mpegtsmux ! hlssink location=/mnt/tmp/segment%05d.ts playlist-location=/mnt/tmp/playlist.m3u8 max-files=5 playlist-length=2 playlist-root="http://192.168.0.40/" target-duration=2
コマンドの詳細は公式ドキュメントを参照してほしい。
躓いたポイント
暗い環境下でのC920の動作
30FPSを指定していても、暗い環境では15FPSに自動的に下がるらしい。結果として音声とタイミングが合わなくなり、以下のエラーが出る。
WARNING: Can't record audio fast enough Dropped *** samples. This is most likely because downstream can't keep up and is consuming samples too slowly.
いろいろ設定を試したが、この動作を無効にすることはできなかった。最終的に常に15FPSで録画することで回避した。
ファイル名に時間を付けて分割保存
Splitmuxsinkを使えば一定時間あるいはサイズごとに映像をファイルに分割して保存できるらしい。ただし、gst-launchコマンドからは連番での保存でしかできない。
あまり時間を使いたくなかったので、シェルスクリプトで一定時間ごとにgst-launchコマンドを叩き直すことにして回避した。きちんと対処するならばCでプログラムを書く必要がありそう。
Comments
Post a Comment