問題
webカメラを1台だけ挿すのなら、通常は/dev/video0
に繋げばいいと思う
$ fswebcam -d /dev/video0 a.jpg
# またはデフォルトで/dev/video0なので
$ fswebcam a.jpg
しかし、2台以上だとどのカメラが/dev/video0なのか2なのか何なのかわからなくなる。
解決方法
v4l2-ctlを使うとこういうリストが出力できる。
raspberryPiでの例
$ v4l2-ctl --list-devices
bcm2835-codec-decode (platform:bcm2835-codec):
/dev/video10
/dev/video11
/dev/video12
bcm2835-isp (platform:bcm2835-isp):
/dev/video13
/dev/video14
/dev/video15
/dev/video16
BUFFALO BSW32KM03 USB PC Camera (usb-20980000.usb-1.3):
/dev/video0
/dev/video1
UVC Camera (046d:0825) (usb-20980000.usb-1.5):
/dev/video2
/dev/video3
ここで注目するのは、カメラには(usb-20980000.usb-1.5)
的なのがついているということ。
そしてこのusb-1.5
の部分は物理的なUSBポートに紐付けられている(参考)。
なので、webカメラを常時挿したままであれば、そのカメラのここで言うUSB番号が固定されるので、その下に書いてある最初のパス(/dev/video*
)を使うとカメラの画像が取れる(もう一方はメタデータ?らしい)。
これらを踏まえての簡単なrubyスクリプト
require "./video_paths"
VideoPaths.paths # => {"1.3"=>"/dev/video0", "1.5"=>"/dev/video2"}
video_paths.rb
require "memoist"
require "active_support/core_ext/object/blank"
class VideoPaths
USB_NUMBER_REG = /\.usb\-([\d\.]+)/
class << self
extend Memoist
def paths
new.to_h
end
memoize :paths
end
def initialize
@output = clean_output(`v4l2-ctl --list-devices`)
end
def to_h
camera_names.to_h do |camera_name|
key, valid_path, *other_paths = group_by_device[camera_name]
[extract_usb_number(camera_name), valid_path]
end
end
private
attr_reader :output
def group_by_device
key = :not_yet
output.group_by do |line|
key = line if line.end_with?(":")
key
end
end
# BUFFALO BSW32KM03 USB PC Camera (usb-20980000.usb-1.3):
# ^^^^^^^^
def camera_names
group_by_device.keys.select { |key| key.match?(/camera/i) }
end
# BUFFALO BSW32KM03 USB PC Camera (usb-20980000.usb-1.3):
# ^^^^^^^^
def extract_usb_number(camera_name)
camera_name.match(USB_NUMBER_REG)[1]
end
def clean_output(text)
text.lines.collect(&:strip).delete_if(&:blank?)
end
end