Raspberry Piに接続されているwebカメラの情報をv4l2-ctlで簡単に取得したい

v4l2-ctlを使って現在接続されているwebカメラの解像度情報を知るために簡単なスクリプトを作りました。
2020.04.17

こんにちはCX事業本部のさかじです。
現在接続されているwebカメラの解像度情報を知るために、v4l2-ctlというツールを使ってみました。ついでに出力されたデータをちょっと整形してみました。

環境

  • Raspberry Pi3 Model B+

前提条件

$ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 10 (buster)
Release:        10
Codename:       buster

$ uname -a
Linux ykg-base-dev1 4.19.97-v7+ #1294 SMP Thu Jan 30 13:15:58 GMT 2020 armv7l GNU/Linux

$ python3 --version
Python 3.7.3

インストール

$ sudo apt-get install v4l-utils

デバイスリスト

$ v4l2-ctl --list-devices
bcm2835-codec-decode (platform:bcm2835-codec):
        /dev/video10
        /dev/video11
        /dev/video12

BUFFALO BSW32KM03 USB PC Camera (usb-3f980000.usb-1.1.2):
        /dev/video0
        /dev/video1

/dev/video10 ~ 12v4l2-ctlで使用するループバックデバイスのようです。
参考

解像度情報取得

$ v4l2-ctl --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
        Type: Video Capture

        [0]: 'MJPG' (Motion-JPEG, compressed)
                Size: Discrete 640x480
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 1280x720
                        Interval: Discrete 0.050s (20.000 fps)
                Size: Discrete 1280x800
                        Interval: Discrete 0.050s (20.000 fps)
                Size: Discrete 1920x1080
                        Interval: Discrete 0.050s (20.000 fps)
                Size: Discrete 352x288
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 320x240
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 176x144
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 160x120
                        Interval: Discrete 0.033s (30.000 fps)
                Size: Discrete 2016x1512
                        Interval: Discrete 0.067s (15.000 fps)

複数カメラが接続されている場合にはデバイスを割り当てる必要があります。

$ v4l2-ctl --list-devices
bcm2835-codec-decode (platform:bcm2835-codec):
        /dev/video10
        /dev/video11
        /dev/video12

BUFFALO BSW32KM03 USB PC Camera (usb-3f980000.usb-1.1.2):
        /dev/video0
        /dev/video1

USB 2.0 PC Camera: PC Camera (usb-3f980000.usb-1.3):
        /dev/video2
        /dev/video3


$ v4l2-ctl --device /dev/video2 --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
        Type: Video Capture

        [0]: 'YUYV' (YUYV 4:2:2)
                Size: Discrete 640x480
                        Interval: Discrete 0.033s (30.000 fps)

/dev/video1って何だろう?

カメラをRaspberry Piへ接続すると/video0/video1が見えます。その正体をみてみました。
video0と同じようにメーカなどデバイスの情報は見えますが、video関係の情報は出力されません。このことで使えないのはわかったのですが、なぜもう一つ出力されているかはわかりませんが、video10~12と同様にバッファとして使用しているのでしょうか。

$ v4l2-ctl --device /dev/video1 --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
        Type: Video Capture

$ v4l2-ctl --device /dev/video1 --all
Driver Info:
        Driver name      : uvcvideo
        Card type        : BUFFALO BSW32KM03 USB PC Camera
        Bus info         : usb-3f980000.usb-1.1.2
        Driver version   : 4.19.97
        Capabilities     : 0x84a00001
                Video Capture
                Metadata Capture
                Streaming
                Extended Pix Format
                Device Capabilities
        Device Caps      : 0x04a00000
                Metadata Capture
                Streaming
                Extended Pix Format
Media Driver Info:
        Driver name      : uvcvideo
        Model            : BUFFALO BSW32KM03 USB PC Camera
        Serial           : 
        Bus info         : usb-3f980000.usb-1.1.2
        Media version    : 4.19.97
        Hardware revision: 0x00000002 (2)
        Driver version   : 4.19.97
Interface Info:
        ID               : 0x03000005
        Type             : V4L Video
Entity Info:
        ID               : 0x00000004 (4)
        Name             : BUFFALO BSW32KM03 USB PC Camera
        Function         : V4L2 I/O
Priority: 2

使いやすいようにPythonでサイズだけ抜き出してみた

cam_list_test.py

import subprocess

def main():
    cmd = 'v4l2-ctl --device /dev/video0 --list-formats-ext'
    proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
    outs_bytes = proc.communicate()[0]
    outs_str = outs_bytes.decode('utf-8')
    outs_str_lists = outs_str.split('\n')

    for line in outs_str_lists:
        line_lists = line.split()
        if len(line_lists) > 0 and line_lists[0] == 'Size:':
            print(line_lists)



if __name__ == '__main__':
    main()

手持ちのカメラをRaspberry Piに接続してリストを取ってみた

$ python3 cam_list_test.py
['Size:', 'Discrete', '640x480']
['Size:', 'Discrete', '1280x720']
['Size:', 'Discrete', '1280x800']
['Size:', 'Discrete', '1920x1080']
['Size:', 'Discrete', '352x288']
['Size:', 'Discrete', '320x240']
['Size:', 'Discrete', '176x144']
['Size:', 'Discrete', '160x120']
['Size:', 'Discrete', '2016x1512']

これでちょっと使いやすくなりますね

参考サイト

debian/V4L2-CTL(1)
Python3 サブプロセス管理

最後に

OpenCVに上記のような機能があるか探してみたのですが、私には見つけられませんでした。組み込み開発時代のころはなければ作っていたのですが便利な機能も使って、ちょっとでも開発工数を減らしたいですね。