feat: show a crossed-out camera when another app uses it

This commit is contained in:
Felitendo committed 2026-09-28 14:34:40 +02:00
1 parent ac38638dd4
commit 5eb9ea7438
29 files changed
+1940 -1235

No files matched your search

+32
View File
@@ -15,6 +15,7 @@
#include <unistd.h>
#include <algorithm>
#include <cerrno>
#include <thread>
using namespace std::chrono;
@@ -105,6 +106,24 @@ bool probe(const QString &path, CameraInfo *info)
}
return ok;
}
// A program that streams holds the camera's buffers. Asking for none is how
// V4L2 lets a program check without taking them: the driver says EBUSY when
// they belong to somebody else.
bool busy(const QString &path)
{
const int fd = ::open(QFile::encodeName(path).constData(), O_RDWR | O_NONBLOCK | O_CLOEXEC);
if (fd < 0) {
return errno == EBUSY;
}
v4l2_requestbuffers req{};
req.count = 0;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
const bool result = ::ioctl(fd, VIDIOC_REQBUFS, &req) != 0 && errno == EBUSY;
::close(fd);
return result;
}
} // namespace
Camera::Camera() = default;
@@ -142,6 +161,15 @@ QString Camera::autoPath()
return cameras.isEmpty() ? QString() : cameras.first().path;
}
bool Camera::inUse(const QString &spec)
{
if (spec.startsWith(u"file:") || spec.startsWith(u"images:")) {
return false;
}
const QString path = spec.isEmpty() || spec == u"auto" ? autoPath() : spec;
return !path.isEmpty() && busy(path);
}
bool Camera::open(const QString &spec, QString *error)
{
close();
@@ -178,6 +206,10 @@ bool Camera::open(const QString &spec, QString *error)
*error = QStringLiteral("%1 is not a camera").arg(path);
return false;
}
if (busy(path)) {
*error = QStringLiteral("%1 is in use by another program").arg(path);
return false;
}
if (!m_capture.open(QFile::encodeName(path).toStdString(), cv::CAP_V4L2) || !m_capture.isOpened()) {
*error = QStringLiteral("cannot open %1 (in use by another program?)").arg(path);
+4
View File
@@ -55,6 +55,10 @@ public:
// What "auto" means on this machine: the first colour camera, else the
// first camera at all.
static QString autoPath();
// Whether another program streams from the camera right now, a video
// call for example. Asked without starting it, so the light stays off.
// Never true for a video file or pictures.
static bool inUse(const QString &spec);
private:
bool openImages(const QString &dir, QString *error);