Skip to content

Commit

Permalink
Use /sys/class/video4linux/ to get list of v4l2 devices
Browse files Browse the repository at this point in the history
Signed-off-by: Evan Flynn <[email protected]>
  • Loading branch information
flynneva committed Jan 20, 2024
1 parent f5d3e5b commit 7ff4e65
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 15 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
cmake_minimum_required(VERSION 3.5)
project(usb_cam)

# Default to C++14
# Default to C++17
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD 17)
endif()

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
Expand Down
44 changes: 31 additions & 13 deletions include/usb_cam/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,23 @@ extern "C" {
#include <sys/ioctl.h>
#include <sys/time.h>
#include <unistd.h> // for access

#include <cmath>
#include <ctime>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <sstream>
#include <iostream>
#include <string>
#include <map>

#include "linux/videodev2.h"

#include "usb_cam/constants.hpp"

namespace fs = std::filesystem;


namespace usb_cam
{
Expand Down Expand Up @@ -146,31 +152,43 @@ inline std::map<std::string, v4l2_capability> available_devices()
// Initialize vector of device strings to fill in
std::map<std::string, v4l2_capability> v4l2_devices;

// V4L2 spec says there can only be a maximum of 64 devices
const uint8_t MAX_DEVICES = 64;
// Get a list of all v4l2 devices from /sys/class/video4linux
const std::string v4l2_symlinks_dir = "/sys/class/video4linux/";
for (const auto & device_symlink : fs::directory_iterator(v4l2_symlinks_dir)) {
if (fs::is_symlink(device_symlink)) {
// device_str is the full path to the device in /sys/devices/*
std::string device_str = fs::canonical(
v4l2_symlinks_dir + fs::read_symlink(
device_symlink).generic_string());
// get the proper device name (e.g. /dev/*)
std::ifstream uevent_file(device_str + "/uevent");
std::string line;
std::string device_name;
while (std::getline(uevent_file, line)) {
auto dev_name_index = line.find("DEVNAME=");
if (dev_name_index != std::string::npos) {
device_name = "/dev/" + line.substr(dev_name_index + 8, line.size());
break;
}
}

for (uint8_t i = 0; i < MAX_DEVICES; i++) {
std::string device_str = "/dev/video" + std::to_string(i);
// See if device exists
if (access(device_str.c_str(), F_OK) != -1) {
int fd;
// Try and open device to test access
if ((fd = open(device_str.c_str(), O_RDONLY)) == -1) {
std::cerr << "Cannot open device: `" << device_str << "`, ";
if ((fd = open(device_name.c_str(), O_RDONLY)) == -1) {
std::cerr << "Cannot open device: `" << device_name << "`, ";
std::cerr << "double-check read / write permissions for device" << std::endl;
} else {
struct v4l2_capability device_capabilities = {};

if (xioctl(fd, VIDIOC_QUERYCAP, &device_capabilities) == -1) {
std::cerr << "Could not retrieve device capabilities: `" << device_str;
std::cerr << "Could not retrieve device capabilities: `" << device_name;
std::cerr << "`" << std::endl;
} else {
v4l2_devices[device_str] = device_capabilities;
v4l2_devices[device_name] = device_capabilities;
}
}
} else {
// device doesn't exist, break
break;
// device doesn't exist, continue
continue;
}
}

Expand Down

0 comments on commit 7ff4e65

Please sign in to comment.