Fix query devices on linux
This commit is contained in:
parent
03d6043c08
commit
460c707253
72
src/uvc/uvc-v4l2.cc
Normal file → Executable file
72
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…
Reference in New Issue
Block a user