NanoPi NEOでウェブカメラ

ウェブカメラ

NanoPi NEOの続き。
この手のシングルボードコンピュータを買ってやりたいことの1つは監視カメラ。
シングルボードコンピュータとUSBのウェブカメラがあれば取り敢えずは動画を取得してネットワークに撒くことはできる。しかも非常に低消費電力。

以前にOpenSUSE用ウェブカメラの記事でも書いたがLinuxでウェブカメラを使うのはとても簡単。UVC対応なら特に考えずに接続するだけ。なのでNanoPi NEO + armbian (Linux)でもUVC対応のウェブカメラをUSBポートに繋ぐだけ。

この記事を書く時に実際に使用したウェブカメラ(の広告)

一応接続後に認識されているか確認。

$ ls /dev

video0というのが存在すれば認識されていると思って良い。

それだけじゃ雑すぎだろということならlsusbで見る。

$ lsusb
Bus 008 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 007 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 006 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 004 Device 003: ID 046d:0825 Logitech, Inc. Webcam C270
Bus 004 Device 002: ID 1a40:0101 Terminus Technology Inc. 4-Port HUB
Bus 004 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

上の例だとDevice003にWebcam C270というのが認識されている。

ソフトウエア側は今回はVLCを使うことに。

 # apt-get install vlc

おそらく素のarmbianだとドッサリとパッケージを入れられるだろうけど待ち時間はそんなでもない。

あとはVLCを実行するだけの筈が、ここからが大変。

とりあえずVLCを実行する。

$ cvlc -vvv v4l2:///dev/video0 --sout '#transcode{vcodec=jpeg,acodec=none}:rtp{sdp=rtsp://:8554/}'

おそらくベースとなるコマンドはこんな感じ。
なお、VLCはrootユーザーでは実行できないのでroot以外のユーザーになって実行するか、rootであるならsudoで他のユーザー指定で実行。もっともLinuxの流儀だと基本的にrootでオペレーションしない筈。
上の指定は、入力は/dev/video0 (ウェブカメラ)、ビデオエンコードはMotion JPEG、音声無し、出力はRTSP、ポート番号は本来のRTSPの554ではなく取り敢えず8554。

実行してから他の端末でRTSPで受信して動画を表示する。
例えばWindowsやLinuxにVLCが入っていてそれで表示するなら

$ vlc -vvv rtsp://192.168.0.82:8554/

上はNanoPiのIPアドレスが192.168.0.82の場合
Windowsの場合はVLCのPath付きで実行してやらないとおそらくVLCが起動しない筈。

若しくはVLCプレーヤーを起動して[メディア][ネットワークストリームを開く]を選択、「ネットワークURLを入力して下さい」にrtsp://192.168.0.82:8554/ を入力する。なお、192.168.0.82の部分はNanoPiのIPアドレスを指定。ポート番号の後の / を忘れずに指定。

Motion JPEGなので軽い方ではあるけどNanoPiで動かすとそうでもない不思議。
あと、Motion JPEGでは動画の幅が640pxまで。

armbian用に作られたVLCはPC用の普通とは少し違う様で、VLCで良く使うコーデック名を指定しても殆どがエラーになる。いろいろ試して使えたのはjpeg, mpgv, h264, theoだけ。
次はMPGV (MPEG-2)で実行

$ cvlc -vvv v4l2:///dev/video0 --sout '#transcode{vcodec=mpgv,vb=1200,width=640,height=360,acodec=none}:rtp{sdp=rtsp://:8554/}'

vcodecにmpgvを指定すると共にvb = 帯域、width,height = 動画の横幅,高さを指定。

MPGVは軽いかと思ったがMotion JPEGで遅いくらいなので全然重い (動画が表示されるまでの時間は短い)。そしてなんか扱いにくい。上の指定では帯域を1200Kbps取っているがこれでも画像はかなり荒い。値をもっと大きくするか指定を外すと綺麗。

次はH.264。

$ cvlc -vvv v4l2:///dev/video0 --sout '#transcode{vcodec=h264,width=640,height=360,acodec=none}:rtp{sdp=rtsp://:8554/}'

VLC 1
三角コーンが表示されたままなので失敗かなと思うくらい待たされる。

VLC 2
やっと映ったかなと思ったら暫くこんなの。また、頻繁に動画からこの状態になる。

VLC 3
映った。(上の画像はイメージです)

予想はしてたがアホみたいに重い。動画が表示されるまでに数十秒待たされて、灰色か緑一面が表示されてしばらくしてやっと正常に表示されたかなと思うとすぐに灰色。これじゃ全然使い物にならない。遅延も酷すぎ。
decoder/packetizer fifo full (data not consumed quickly enough), resetting fifo! というメッセージ多発。

そこで、少しはまともに使えるようにオプションを追加。

  • transcodeにthreads=4を追加。これで4コア使う?
  • transcodeにfps=10を追加。動画の動きの滑らかさはなくなるが監視カメラとしては実用的に。
  • transcodeにvenc=x264指定を追加。(以下)
  • vencのx264にpreset=ultrafastを追加。綺麗さより動き最優先。
  • vencのx264にtune=zerolatencyを追加。遅延の少ないチューニング。
  • vencのx264に他幾つか。

こうなった。

$ cvlc -vvv v4l2:///dev/video0 --sout '#transcode{vcodec=h264,venc=x264{preset=ultrafast,tune=zerolatency,intra-refresh,lookahead=10,keyint=15},width=640,height=360,threads=4,fps=10,acodec=none}:rtp{sdp=rtsp://:8554/}'

FPSを10に抑えたこととスレッドを4にしたのがかなり効いたようで移動する被写体の消滅やワープはなくなった。また、遅延も2秒以内と実用に耐える範囲。解像度が640x360でこの程度ならまぁまぁじゃないかな?

できればもっと軽くて柔軟な指定が可能なコーデックを使いたいところだが良い方法あるかな?VLCを作り直す?

2017年2月28日追記
次の記事のクロック変更を行ってCPUを高速化させた上でFPSを10から5~6 (7はギリギリダメかも)程度に落とすと1280x720の解像度でFIFOバッファの溢れ&リセットが発生せずに安定して動くことを確認。ただし、画像は1280x720の解像度を疑いたくなるほどはっきりしない。要するにボケた感じ。