Raspberry PiでUSBカメラ動画をキャプチャしようとしたらselect timeout


Raspberry Piに接続したUSBカメラの映像をストリーミングする場合、OpenCVや、MJPG-streamer、ffmpeg等を使えばできると思いますが、場合によっては、select timeoutというエラーが発生して、カメラ映像をキャプチャできないことがあります。主な原因は、キャプチャ時に高解像度設定をしていて、処理が追い付かないということのようですが、ここでは、解像度を落としたくても落とせない時の対処法を記載します。

念のためラズパイのリリースは下記の通りです。

$ lsb_release -a
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 10 (buster)
Release:        10
Codename:       buster

なぜか低解像度がない

V4L2の--list-formats-extで、接続しているカメラ(この場合は、/dev/device0)の対応フォーマットを確認できます。
私の環境下では、下記の通り、1920x1080と2048x1536しかなく、OpenCV等キャプチャ時の設定で、低解像度を設定しても、「そんなものないから、1920x1080にするよ」と出てきて、その後select timeoutという結果でした。。。

$ v4l2-ctl -d /dev/video0 --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
  Type: Video Capture

  [0]: 'YUYV' (YUYV 4:2:2)
    Size: Discrete 1920x1080
      Interval: Discrete 0.200s (5.000 fps)
    Size: Discrete 2048x1536
      Interval: Discrete 0.333s (3.000 fps)
  [1]: 'MJPG' (Motion-JPEG, compressed)
    Size: Discrete 1920x1080
      Interval: Discrete 0.067s (15.000 fps)
      Interval: Discrete 0.200s (5.000 fps)
    Size: Discrete 2048x1536
      Interval: Discrete 0.100s (10.000 fps)
      Interval: Discrete 0.333s (3.000 fps)

解決方法

V4L2のuserspace(こちら)のVideo Capture Exampleのサンプルソースをコンパイルし、強制的にフォーマットを640x480 YUYVにすることで解決しました。(もしかしたら、直接的解法ではなく、トリガになっただけかもしれませんが)

  1. Video Capture Exampleのmedia/v4l/capture.cをダウンロード
  2. gcc -o capture capture.cでコンパイル
  3. ./capture -f

これで、不思議と下記のように、接続したUSBカメラが低解像度も対応しました。

$ v4l2-ctl -d /dev/video0 --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
  Type: Video Capture

  [0]: 'MJPG' (Motion-JPEG, compressed)
    Size: Discrete 640x480
      Interval: Discrete 0.067s (15.000 fps)
    Size: Discrete 160x120
      Interval: Discrete 0.040s (25.000 fps)
    ...(省略)...
  [1]: 'YUYV' (YUYV 4:2:2)
    Size: Discrete 640x480
      Interval: Discrete 0.067s (15.000 fps)
    Size: Discrete 160x120
      Interval: Discrete 0.040s (25.000 fps)
    ...(省略)...
    Size: Discrete 1920x1080
      Interval: Discrete 0.200s (5.000 fps)
      Interval: Discrete 0.333s (3.000 fps)

mjpg-streamerでストリーミング

mjgp-streamerを使えば、簡単にカメラ映像をWebストリーミングできます。

1. mjpg-streamerのインストール

$ sudo apt update
$ sudo apt install -y cmake libv4l-dev libjpeg-dev imagemagick
$ git clone https://github.com/jacksonliam/mjpg-streamer.git
$ cd mjpg-streamer/mjpg-streamer-experimental
$ sudo make
$ sudo make install

2. ストリーミング起動用スクリプト

mjpg-streamer/mjpg-streamer-experimentalフォルダ下にシェルスクリプトを作成します。

start_stream.sh
#!/bin/sh
PORT="8080" #ポート番号
SIZE="640x480" #画面サイズ
FRAMERATE="15" #フレームレート
export LD_LIBRARY_PATH=/usr/local/lib
mjpg_streamer \
-i "input_uvc.so -f $FRAMERATE -r $SIZE -d /dev/video0 -y -n" \
-o "output_http.so -w ./www -p $PORT"

作成シェルスクリプトを起動し、成功すると、下記のようになります。

$ sh start_stream.sh
MJPG Streamer Version: git rev: 310b29f4a94c46652b20c4b7b6e5cf24e532af39
 i: Using V4L2 device.: /dev/video0
 i: Desired Resolution: 640 x 480
 i: Frames Per Second.: 15
 i: Format............: YUYV
 i: JPEG Quality......: 80
 i: TV-Norm...........: DEFAULT
 o: www-folder-path......: ./www/
 o: HTTP TCP port........: 8080
 o: HTTP Listen Address..: (null)
 o: commands.............: enabled

3. ブラウザからストリーミング配信を確認する

下記URLにアクセスするだけです。
http://[RaspberryPiのIPアドレス]:8080
左メニューのStreamを選択すると、配信映像を確認することができます。