Fix query devices on linux
This commit is contained in:
		
							parent
							
								
									03d6043c08
								
							
						
					
					
						commit
						460c707253
					
				
							
								
								
									
										76
									
								
								src/uvc/uvc-v4l2.cc
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										76
									
								
								src/uvc/uvc-v4l2.cc
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							@ -29,15 +29,31 @@ namespace uvc {
 | 
				
			|||||||
  } while (0)
 | 
					  } while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 | 
					class device_error : public std::exception {
 | 
				
			||||||
 | 
					 public:
 | 
				
			||||||
 | 
					  explicit device_error(const std::string &what_arg) noexcept
 | 
				
			||||||
 | 
					      : what_message_(std::move(what_arg)) {}
 | 
				
			||||||
 | 
					  explicit device_error(const char *what_arg) noexcept
 | 
				
			||||||
 | 
					      : what_message_(std::move(what_arg)) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const char *what() const noexcept {
 | 
				
			||||||
 | 
					    return what_message_.c_str();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  std::string what_message_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct throw_error {
 | 
					struct throw_error {
 | 
				
			||||||
  throw_error() {}
 | 
					  throw_error() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  explicit throw_error(const std::string &s) {
 | 
					  explicit throw_error(const std::string &s) {
 | 
				
			||||||
    ss << s;
 | 
					    ss << s;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ~throw_error() {
 | 
					  ~throw_error() noexcept(false) {
 | 
				
			||||||
    throw std::runtime_error(ss.str());
 | 
					    throw std::runtime_error(ss.str());
 | 
				
			||||||
 | 
					    // throw device_error(ss.str());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  template<class T>
 | 
					  template<class T>
 | 
				
			||||||
@ -48,7 +64,6 @@ struct throw_error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  std::ostringstream ss;
 | 
					  std::ostringstream ss;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int xioctl(int fh, int request, void *arg) {
 | 
					static int xioctl(int fh, int request, void *arg) {
 | 
				
			||||||
  int r;
 | 
					  int r;
 | 
				
			||||||
@ -77,7 +92,6 @@ struct device {
 | 
				
			|||||||
  const std::shared_ptr<context> parent;
 | 
					  const std::shared_ptr<context> parent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string dev_name;  // Device name (typically of the form /dev/video*)
 | 
					  std::string dev_name;  // Device name (typically of the form /dev/video*)
 | 
				
			||||||
  int busnum, devnum, parent_devnum;  // USB device bus number and device number
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  std::string name;  // Device description name
 | 
					  std::string name;  // Device description name
 | 
				
			||||||
  int vid, pid, mi;  // Vendor ID, product ID, and multiple interface index
 | 
					  int vid, pid, mi;  // Vendor ID, product ID, and multiple interface index
 | 
				
			||||||
@ -98,72 +112,52 @@ struct device {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    struct stat st;
 | 
					    struct stat st;
 | 
				
			||||||
    if (stat(dev_name.c_str(), &st) < 0) {  // file status
 | 
					    if (stat(dev_name.c_str(), &st) < 0) {  // file status
 | 
				
			||||||
      LOG(FATAL) << "Cannot identify '" << dev_name << "': " << errno << ", "
 | 
					      throw_error() << "Cannot identify '" << dev_name << "': " << errno << ", "
 | 
				
			||||||
                 << strerror(errno);
 | 
					                    << strerror(errno);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (!S_ISCHR(st.st_mode)) {  // character device?
 | 
					    if (!S_ISCHR(st.st_mode)) {  // character device?
 | 
				
			||||||
      LOG(FATAL) << dev_name << " is no device";
 | 
					      throw_error() << dev_name << " is no device";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Search directory and up to three parent directories to find busnum/devnum
 | 
					 | 
				
			||||||
    std::ostringstream ss;
 | 
					 | 
				
			||||||
    ss << "/sys/dev/char/" << major(st.st_rdev) << ":" << minor(st.st_rdev)
 | 
					 | 
				
			||||||
       << "/device/";
 | 
					 | 
				
			||||||
    auto path = ss.str();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool good = false;
 | 
					 | 
				
			||||||
    for (int i = 0; i <= 3; ++i) {
 | 
					 | 
				
			||||||
      if (std::ifstream(path + "busnum") >> busnum) {
 | 
					 | 
				
			||||||
        if (std::ifstream(path + "devnum") >> devnum) {
 | 
					 | 
				
			||||||
          if (std::ifstream(path + "../devnum") >> parent_devnum) {
 | 
					 | 
				
			||||||
            good = true;
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      path += "../";
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (!good)
 | 
					 | 
				
			||||||
      LOG(FATAL) << "Failed to read busnum/devnum";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!(std::ifstream("/sys/class/video4linux/" + name + "/name") >>
 | 
					    if (!(std::ifstream("/sys/class/video4linux/" + name + "/name") >>
 | 
				
			||||||
          this->name))
 | 
					          this->name))
 | 
				
			||||||
      LOG(FATAL) << "Failed to read name";
 | 
					      throw_error() << "Failed to read name";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string modalias;
 | 
					    std::string modalias;
 | 
				
			||||||
    if (!(std::ifstream(
 | 
					    if (!(std::ifstream(
 | 
				
			||||||
              "/sys/class/video4linux/" + name + "/device/modalias") >>
 | 
					              "/sys/class/video4linux/" + name + "/device/modalias") >>
 | 
				
			||||||
          modalias))
 | 
					          modalias))
 | 
				
			||||||
      LOG(FATAL) << "Failed to read modalias";
 | 
					      throw_error() << "Failed to read modalias";
 | 
				
			||||||
    if (modalias.size() < 14 || modalias.substr(0, 5) != "usb:v" ||
 | 
					    if (modalias.size() < 14 || modalias.substr(0, 5) != "usb:v" ||
 | 
				
			||||||
        modalias[9] != 'p')
 | 
					        modalias[9] != 'p')
 | 
				
			||||||
      LOG(FATAL) << "Not a usb format modalias";
 | 
					      throw_error() << "Not a usb format modalias";
 | 
				
			||||||
    if (!(std::istringstream(modalias.substr(5, 4)) >> std::hex >> vid))
 | 
					    if (!(std::istringstream(modalias.substr(5, 4)) >> std::hex >> vid))
 | 
				
			||||||
      LOG(FATAL) << "Failed to read vendor ID";
 | 
					      throw_error() << "Failed to read vendor ID";
 | 
				
			||||||
    if (!(std::istringstream(modalias.substr(10, 4)) >> std::hex >> pid))
 | 
					    if (!(std::istringstream(modalias.substr(10, 4)) >> std::hex >> pid))
 | 
				
			||||||
      LOG(FATAL) << "Failed to read product ID";
 | 
					      throw_error() << "Failed to read product ID";
 | 
				
			||||||
    if (!(std::ifstream(
 | 
					    if (!(std::ifstream(
 | 
				
			||||||
              "/sys/class/video4linux/" + name + "/device/bInterfaceNumber") >>
 | 
					              "/sys/class/video4linux/" + name + "/device/bInterfaceNumber") >>
 | 
				
			||||||
          std::hex >> mi))
 | 
					          std::hex >> mi))
 | 
				
			||||||
      LOG(FATAL) << "Failed to read interface number";
 | 
					      throw_error() << "Failed to read interface number";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fd = open(dev_name.c_str(), O_RDWR | O_NONBLOCK, 0);
 | 
					    fd = open(dev_name.c_str(), O_RDWR | O_NONBLOCK, 0);
 | 
				
			||||||
    if (fd < 0) {
 | 
					    if (fd < 0) {
 | 
				
			||||||
      LOG(FATAL) << "Cannot open '" << dev_name << "': " << errno << ", "
 | 
					      throw_error() << "Cannot open '" << dev_name << "': " << errno << ", "
 | 
				
			||||||
                 << strerror(errno);
 | 
					                    << strerror(errno);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    v4l2_capability cap = {};
 | 
					    v4l2_capability cap = {};
 | 
				
			||||||
    if (xioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
 | 
					    if (xioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
 | 
				
			||||||
      if (errno == EINVAL)
 | 
					      if (errno == EINVAL)
 | 
				
			||||||
        LOG(FATAL) << dev_name << " is no V4L2 device";
 | 
					        throw_error() << dev_name << " is no V4L2 device";
 | 
				
			||||||
      else
 | 
					      else
 | 
				
			||||||
        LOG_ERROR(FATAL, "VIDIOC_QUERYCAP");
 | 
					        throw_error() << "VIDIOC_QUERYCAP error " << errno << ", "
 | 
				
			||||||
 | 
					                      << strerror(errno);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
 | 
					    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
 | 
				
			||||||
      LOG(FATAL) << dev_name + " is no video capture device";
 | 
					      throw_error() << dev_name + " is no video capture device";
 | 
				
			||||||
    if (!(cap.capabilities & V4L2_CAP_STREAMING))
 | 
					    if (!(cap.capabilities & V4L2_CAP_STREAMING))
 | 
				
			||||||
      LOG(FATAL) << dev_name + " does not support streaming I/O";
 | 
					      throw_error() << dev_name + " does not support streaming I/O";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Select video input, video standard and tune here.
 | 
					    // Select video input, video standard and tune here.
 | 
				
			||||||
    v4l2_cropcap cropcap = {};
 | 
					    v4l2_cropcap cropcap = {};
 | 
				
			||||||
@ -437,7 +431,7 @@ std::vector<std::shared_ptr<device>> query_devices(
 | 
				
			|||||||
    try {
 | 
					    try {
 | 
				
			||||||
      devices.push_back(std::make_shared<device>(context, name));
 | 
					      devices.push_back(std::make_shared<device>(context, name));
 | 
				
			||||||
    } catch (const std::exception &e) {
 | 
					    } catch (const std::exception &e) {
 | 
				
			||||||
      LOG(INFO) << "Not a USB video device: " << e.what();
 | 
					      VLOG(2) << "Not a USB video device: " << e.what();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  closedir(dir);
 | 
					  closedir(dir);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user