diff --git a/uvcengine/uvccameracontrol.cpp b/uvcengine/uvccameracontrol.cpp index 619cce84dfa0e3cf59eefd8fa02011350bb8ae53..18d8d88754e53404e0d4f85929550038a2dba597 100644 --- a/uvcengine/uvccameracontrol.cpp +++ b/uvcengine/uvccameracontrol.cpp @@ -11,9 +11,9 @@ UVCCameraControl::UVCCameraControl(QObject *parent) , m_state(QCamera::UnloadedState) , m_captureMode(QCamera::CaptureStillImage) { - m_session = qobject_cast(parent); + m_session = qobject_cast(parent); //connect(m_session, SIGNAL(statusChanged(QCamera::Status)), - // this, SIGNAL(statusChanged(QCamera::Status))); + // this, SIGNAL(statusChanged(QCamera::Status))); } UVCCameraControl::~UVCCameraControl() diff --git a/uvcengine/uvccameracontrol.h b/uvcengine/uvccameracontrol.h index 33fe02716be8e473f2e06986c2382e4bb30e1d33..f7e89d7b05f0f0a550de8877c5c07ae5c8e49a1d 100644 --- a/uvcengine/uvccameracontrol.h +++ b/uvcengine/uvccameracontrol.h @@ -20,7 +20,7 @@ public: QCamera::State state() const { return m_state; } QCamera::CaptureModes captureMode() const { return m_captureMode; } - void setCaptureMode(QCamera::CaptureModes mode); + void setCaptureMode(QCamera::CaptureModes mode); void setState(QCamera::State state); diff --git a/uvcengine/uvccamerasession.cpp b/uvcengine/uvccamerasession.cpp index 650eb19e3230466ac370a69cf4d710734cfdfd96..5947bea14d8268ed528c90aee8d35b97554525ec 100644 --- a/uvcengine/uvccamerasession.cpp +++ b/uvcengine/uvccamerasession.cpp @@ -3,13 +3,16 @@ #include QMutex UVCCameraSession::sessionMutex; +QMap UVCCameraSession::devices; +QMutex UVCCameraSession::devicesMutex; UVCCameraSession::UVCCameraSession(QObject *parent) : QObject(parent), m_surface(Q_NULLPTR), streaming(false), bandwidthFactor(1.3f), - interval(0), + interval(0), + ctx(NULL), dev(NULL), devh(NULL) { @@ -17,12 +20,60 @@ UVCCameraSession::UVCCameraSession(QObject *parent) UVCCameraSession::~UVCCameraSession() { - unload(); + unload(); + release(deviceName); + if (ctx) + uvc_exit(ctx); } -void UVCCameraSession::setDevice(uvc_device_t *device) +bool UVCCameraSession::setDevice(const QString &device) { - dev = device; + if ( ! acquire(device) ) { + qWarning() << device << "already in use."; + return false; + } + + uvc_error_t res; + if (!ctx) { + res = uvc_init(&ctx, NULL); + if (res < 0) { + qWarning() << "uvc_init" << uvc_strerror(res); + ctx = NULL; + return false; + } + } + + uvc_device_t **devList; + res = uvc_get_device_list(ctx, &devList); + if (res < 0) { + qWarning() << "uvc_get_device_list" << uvc_strerror(res); + return false; + } + + bool ret = false; + int idx = 0; + while (1) { + dev = devList[idx]; + idx++; + if (dev == NULL) + break; + uvc_device_descriptor_t *desc; + res = uvc_get_device_descriptor(dev, &desc); + if (res < 0) { + qWarning() << "uvc_get_device_descriptor" << uvc_strerror(res); + return false; + } + QString product(desc->product); + uvc_free_device_descriptor(desc); + + if (product.compare(device) == 0) { + deviceName = device; + ret = true; + break; + } + } + uvc_free_device_list(devList, 0); + return ret; } void UVCCameraSession::setSurface(QAbstractVideoSurface* surface) @@ -67,14 +118,14 @@ void UVCCameraSession::presentFrame(QVideoFrame frame, const qreal t) qreal latency = frameReference.elapsed() - t; frame.setMetaData("timestamp", t); if (latency <= MAX_LATENCY_MS && m_surface) - m_surface->present(frame); + m_surface->present(frame); //else // qWarning() << "Dropping frame (" << latency << "ms old )"; } bool UVCCameraSession::load() { - QMutexLocker sessionLocker(&sessionMutex); + QMutexLocker sessionLocker(&sessionMutex); uvc_error_t res; if (!dev) @@ -111,12 +162,13 @@ bool UVCCameraSession::unload() QMutexLocker sessionLocker(&sessionMutex); if (streaming) - stopPreview(); + stopPreview(); + #ifdef _WIN32 // TODO: closing here seems to mess up the device - //if (devh) - // uvc_close(devh); - //devh = NULL; + //if (devh) + // uvc_close(devh); + devh = NULL; #else // For linux it seems to work as expected if (devh) @@ -136,7 +188,7 @@ void concurrentCustomCallback(UVCCameraSession *session) continue; uvc_frame_t *frame = NULL; uvc_error_t res; - res = uvc_stream_get_frame(session->strmh, &frame, 0); + res = uvc_stream_get_frame(session->strmh, &frame, 0); if ( res == UVC_SUCCESS && frame != NULL) session->callback(frame); else @@ -265,7 +317,8 @@ bool UVCCameraSession::stopPreview() break; if (res != UVC_SUCCESS && res != UVC_ERROR_INVALID_PARAM) qWarning() << "uvc_stream_stop" << uvc_strerror(res); - uvc_stream_close(strmh); + uvc_stream_close(strmh); + strmh = NULL; frameReference.invalidate(); return true; @@ -310,3 +363,19 @@ bool UVCCameraSession::isPupilEyeCamera() uvc_free_device_descriptor(desc); return ret; } + +bool UVCCameraSession::acquire(const QString &device) +{ + QMutexLocker locker(&devicesMutex); + if (devices.contains(device)) + return false; + devices[device] = true; + return true; +} + +void UVCCameraSession::release(const QString &device) +{ + QMutexLocker locker(&devicesMutex); + if (devices.contains(device)) + devices.remove(device); +} diff --git a/uvcengine/uvccamerasession.h b/uvcengine/uvccamerasession.h index 3e481deeef0d28fcd0d911351bf4b5cd66eef078..5e53e5cf3d595ef9f371f8b8ec031c8250e4fac5 100644 --- a/uvcengine/uvccamerasession.h +++ b/uvcengine/uvccamerasession.h @@ -41,7 +41,7 @@ public: QCameraViewfinderSettings viewfinderSettings(); void setViewfinderSettings(const QCameraViewfinderSettings &settings); - void setDevice(uvc_device_t *device); + bool setDevice(const QString &device); bool load(); bool unload(); @@ -52,7 +52,7 @@ public: bool streaming; uvc_stream_handle_t *strmh; QMutex getFrameMutex; - double interval; + double interval; private Q_SLOTS: void presentFrame(QVideoFrame frame, const qreal t); @@ -61,10 +61,12 @@ private: float bandwidthFactor; QCamera::Status m_status; QAbstractVideoSurface *m_surface; - QMutex surfaceMutex; + QMutex surfaceMutex; + QString deviceName; // Source (camera) - uvc_device_t *dev; + uvc_context_t* ctx; + uvc_device_t *dev; uvc_device_handle_t *devh; uvc_stream_ctrl_t ctrl; @@ -83,7 +85,13 @@ private: static QMutex sessionMutex; bool isPupilFieldCamera(); - bool isPupilEyeCamera(); + bool isPupilEyeCamera(); + + // device availability + static QMap UVCCameraSession::devices; + static QMutex UVCCameraSession::devicesMutex; + bool acquire(const QString &device); + void release(const QString &device); }; diff --git a/uvcengine/uvcengine.pro b/uvcengine/uvcengine.pro index be8792d4fe0ff1694c3f617082574d576ba1e9b9..7891bbf0a5d88159d29cc8defd3b8e337038a921 100644 --- a/uvcengine/uvcengine.pro +++ b/uvcengine/uvcengine.pro @@ -39,9 +39,9 @@ unix { # Dependencies win32:{ - LIBUSBPATH = "C:/Users/santini/repo/libusb/" - LIBUVCPATH = "C:/Users/santini/repo/libuvc/" - LIBPTHREADSPATH = "C:/Users/santini/repo/libuvc/pthreads-2.9.1/" + LIBUSBPATH = "C:/Users/santini/repo/libusb/" + LIBUVCPATH = "C:/Users/santini/repo/libuvc/" + LIBPTHREADSPATH = "C:/Users/santini/repo/libuvc/pthreads-2.9.1/" # Libraries required to access pupil lab's cameras # LIBUSB-1.0 @@ -56,8 +56,9 @@ win32:{ LIBS += -llibusb-1.0 # LIBUVC - INCLUDEPATH += "$${LIBUVCPATH}/install/include/" - contains(QMAKE_HOST.arch, x86_64) { + INCLUDEPATH += "$${LIBUVCPATH}/include/" + INCLUDEPATH += "$${LIBUVCPATH}/build/include/" + contains(QMAKE_HOST.arch, x86_64) { Release:LIBS += "-L$${LIBUVCPATH}/build/Release/" Debug:LIBS += "-L$${LIBUVCPATH}/build/Debug" } else { diff --git a/uvcengine/uvcvideodevicecontrol.cpp b/uvcengine/uvcvideodevicecontrol.cpp index 9addda8bcaeb7a9700b57d14900fd7125dafd5ac..9e1174d858422ebfb068240e045468c8f5be57f4 100644 --- a/uvcengine/uvcvideodevicecontrol.cpp +++ b/uvcengine/uvcvideodevicecontrol.cpp @@ -4,23 +4,24 @@ QT_BEGIN_NAMESPACE Q_GLOBAL_STATIC(QList, deviceList) -// this context may never get deleted. Is that a problem? -uvc_context_t* UVCVideoDeviceControl::ctx = NULL; -QMap UVCVideoDeviceControl::busyDevices; +bool UVCVideoDeviceControl::loaded = false; UVCVideoDeviceControl::UVCVideoDeviceControl(QObject *parent) - : QVideoDeviceSelectorControl(parent), - currentDevice(""), + : QVideoDeviceSelectorControl(parent), + ctx(NULL), selected(0) { - m_session = qobject_cast(parent); - updateDevices(); + m_session = qobject_cast(parent); + updateDevices(); + + if (!loaded) { + loaded = true; + qInfo() << "Loaded uvcengine!"; + } } UVCVideoDeviceControl::~UVCVideoDeviceControl() { - busyDevices.remove(currentDevice); - currentDevice.clear(); } int UVCVideoDeviceControl::deviceCount() const @@ -66,44 +67,9 @@ void UVCVideoDeviceControl::setSelectedDevice(int index) if (index >= 0 && index < deviceList->count()) { if (m_session) { QString device = deviceList->at(index).first; - - uvc_device_t **devList; - uvc_error_t res; - res = uvc_get_device_list(ctx, &devList); - if (res < 0) { - qWarning() << "uvc_get_device_list" << uvc_strerror(res); - return; - } - - int idx = 0; - while (1) { - uvc_device_t *dev = devList[idx]; - idx++; - if (dev == NULL) - break; - uvc_device_descriptor_t *desc; - res = uvc_get_device_descriptor(dev, &desc); - if (res < 0) { - qWarning() << "uvc_get_device_descriptor" << uvc_strerror(res); - return; - } - bool selectedDevice = QString(desc->product).compare(device) == 0; - uvc_free_device_descriptor(desc); - - if (selectedDevice) { - if (!busyDevices.contains(device)) { - busyDevices[device] = true; - currentDevice = device; - m_session->setDevice(dev); - } else { - qWarning() << "Device is busy."; - } - break; - } - } - uvc_free_device_list(devList, 0); + if ( m_session->setDevice(device) ) + selected = index; } - selected = index; } } @@ -117,23 +83,18 @@ void UVCVideoDeviceControl::updateDevices() { static QElapsedTimer timer; if (timer.isValid() && timer.elapsed() < 500) // ms - return; + return; deviceList->clear(); - uvc_error_t res; - - if (!ctx) { - // Init libuvc - qInfo() << "Initializing libuvc context..."; - res = uvc_init(&ctx, NULL); - if (res < 0) { - qWarning() << "uvc_init" << uvc_strerror(res); - return; - } - } - - uvc_device_t **devList; + uvc_error_t res; + uvc_context_t *ctx; + res = uvc_init(&ctx, NULL); + if (res < 0) { + qWarning() << "uvc_init" << uvc_strerror(res); + return ; + } + uvc_device_t **devList; res = uvc_get_device_list(ctx, &devList); if (res < 0) { qWarning() << "uvc_get_device_list" << uvc_strerror(res); @@ -166,7 +127,8 @@ void UVCVideoDeviceControl::updateDevices() uvc_free_device_descriptor(desc); } - uvc_free_device_list(devList, 0); + uvc_free_device_list(devList, 0); + uvc_exit(ctx); timer.restart(); } diff --git a/uvcengine/uvcvideodevicecontrol.h b/uvcengine/uvcvideodevicecontrol.h index 3ee9f746d5fd83960fc44ee5dcbad167bd55abf1..37a6f66436b5471886e423e90478182b3966e996 100644 --- a/uvcengine/uvcvideodevicecontrol.h +++ b/uvcengine/uvcvideodevicecontrol.h @@ -27,19 +27,18 @@ public: int defaultDevice() const; int selectedDevice() const; - static const QList &availableDevices(); + static const QList &availableDevices(); public Q_SLOTS: void setSelectedDevice(int index); private: - static void updateDevices(); + static void updateDevices(); UVCCameraSession* m_session; int selected; - static uvc_context_t* ctx; - static QMap busyDevices; - QString currentDevice; + uvc_context_t* ctx; + static bool loaded; }; QT_END_NAMESPACE