DirectShow: correctly update camera list.
authorYoann Lopes <yoann.lopes@theqtcompany.com>
Thu, 9 Apr 2015 14:09:39 +0000 (16:09 +0200)
committerYoann Lopes <yoann.lopes@theqtcompany.com>
Tue, 14 Apr 2015 14:49:56 +0000 (14:49 +0000)
8923c0ff fixed the list not being updated after plugging/unplugging a
camera from the system. However, it was only a partial fix affecting
only QCameraInfo::availableCameras(). DSVideoDeviceControl was still
internally keeping a list of cameras that was never updated, causing
the QCamera constructor to not take into account new or removed
cameras.

Change-Id: Ie5e79c46002017b1e85bfc53c6391a2a747361a0
Task-number: QTBUG-39708
Reviewed-by: Christian Stromme <christian.stromme@theqtcompany.com>
src/plugins/directshow/camera/dsvideodevicecontrol.cpp
src/plugins/directshow/camera/dsvideodevicecontrol.h
src/plugins/directshow/dsserviceplugin.cpp
src/plugins/directshow/dsserviceplugin.h

index 8692994..c3d23e0 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <QDebug>
 #include <QFile>
+#include <qelapsedtimer.h>
 
 #include "dsvideodevicecontrol.h"
 #include "dscamerasession.h"
@@ -48,33 +49,37 @@ extern const CLSID CLSID_VideoInputDeviceCategory;
 
 QT_BEGIN_NAMESPACE
 
+Q_GLOBAL_STATIC(QList<DSVideoDeviceInfo>, deviceList)
+
 DSVideoDeviceControl::DSVideoDeviceControl(QObject *parent)
     : QVideoDeviceSelectorControl(parent)
 {
     m_session = qobject_cast<DSCameraSession*>(parent);
-
-    enumerateDevices(&m_devices, &m_descriptions);
-
     selected = 0;
 }
 
 int DSVideoDeviceControl::deviceCount() const
 {
-    return m_devices.count();
+    updateDevices();
+    return deviceList->count();
 }
 
 QString DSVideoDeviceControl::deviceName(int index) const
 {
-    if (index >= 0 && index <= m_devices.count())
-        return QString::fromUtf8(m_devices.at(index).constData());
+    updateDevices();
+
+    if (index >= 0 && index <= deviceList->count())
+        return QString::fromUtf8(deviceList->at(index).first.constData());
 
     return QString();
 }
 
 QString DSVideoDeviceControl::deviceDescription(int index) const
 {
-    if (index >= 0 && index <= m_descriptions.count())
-        return m_descriptions.at(index);
+    updateDevices();
+
+    if (index >= 0 && index <= deviceList->count())
+        return deviceList->at(index).second;
 
     return QString();
 }
@@ -89,10 +94,34 @@ int DSVideoDeviceControl::selectedDevice() const
     return selected;
 }
 
-void DSVideoDeviceControl::enumerateDevices(QList<QByteArray> *devices, QStringList *descriptions)
+void DSVideoDeviceControl::setSelectedDevice(int index)
 {
-    devices->clear();
-    descriptions->clear();
+    updateDevices();
+
+    if (index >= 0 && index < deviceList->count()) {
+        if (m_session) {
+            QString device = deviceList->at(index).first;
+            if (device.startsWith("ds:"))
+                device.remove(0,3);
+            m_session->setDevice(device);
+        }
+        selected = index;
+    }
+}
+
+const QList<DSVideoDeviceInfo> &DSVideoDeviceControl::availableDevices()
+{
+    updateDevices();
+    return *deviceList;
+}
+
+void DSVideoDeviceControl::updateDevices()
+{
+    static QElapsedTimer timer;
+    if (timer.isValid() && timer.elapsed() < 500) // ms
+        return;
+
+    deviceList->clear();
 
     ICreateDevEnum* pDevEnum = NULL;
     IEnumMoniker* pEnum = NULL;
@@ -116,7 +145,9 @@ void DSVideoDeviceControl::enumerateDevices(QList<QByteArray> *devices, QStringL
                 if (SUCCEEDED(hr)) {
                     QString output(QString::fromWCharArray(strName));
                     mallocInterface->Free(strName);
-                    devices->append(output.toUtf8().constData());
+
+                    DSVideoDeviceInfo devInfo;
+                    devInfo.first = output.toUtf8();
 
                     IPropertyBag *pPropBag;
                     hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)(&pPropBag));
@@ -130,7 +161,9 @@ void DSVideoDeviceControl::enumerateDevices(QList<QByteArray> *devices, QStringL
                         }
                         pPropBag->Release();
                     }
-                    descriptions->append(output);
+                    devInfo.second = output;
+
+                    deviceList->append(devInfo);
                 }
                 pMoniker->Release();
             }
@@ -139,19 +172,8 @@ void DSVideoDeviceControl::enumerateDevices(QList<QByteArray> *devices, QStringL
         }
         pDevEnum->Release();
     }
-}
 
-void DSVideoDeviceControl::setSelectedDevice(int index)
-{
-    if (index >= 0 && index < m_devices.count()) {
-        if (m_session) {
-            QString device = m_devices.at(index);
-            if (device.startsWith("ds:"))
-                device.remove(0,3);
-            m_session->setDevice(device);
-        }
-        selected = index;
-    }
+    timer.restart();
 }
 
 QT_END_NAMESPACE
index a6d4710..0ba7ce3 100644 (file)
@@ -42,6 +42,8 @@ class DSCameraSession;
 
 //QTM_USE_NAMESPACE
 
+typedef QPair<QByteArray, QString> DSVideoDeviceInfo;
+
 class DSVideoDeviceControl : public QVideoDeviceSelectorControl
 {
     Q_OBJECT
@@ -54,17 +56,15 @@ public:
     int defaultDevice() const;
     int selectedDevice() const;
 
-    static void enumerateDevices(QList<QByteArray> *devices, QStringList *descriptions);
+    static const QList<DSVideoDeviceInfo> &availableDevices();
 
 public Q_SLOTS:
     void setSelectedDevice(int index);
 
 private:
-    DSCameraSession* m_session;
-
-    QList<QByteArray> m_devices;
-    QStringList m_descriptions;
+    static void updateDevices();
 
+    DSCameraSession* m_session;
     int selected;
 };
 
index f28f274..f3713f1 100644 (file)
@@ -39,7 +39,6 @@
 #include "dsvideodevicecontrol.h"
 
 #ifdef QMEDIA_DIRECTSHOW_CAMERA
-#include <QtCore/QElapsedTimer>
 #include <dshow.h>
 #include "dscameraservice.h"
 #endif
@@ -122,9 +121,9 @@ QByteArray DSServicePlugin::defaultDevice(const QByteArray &service) const
 {
 #ifdef QMEDIA_DIRECTSHOW_CAMERA
     if (service == Q_MEDIASERVICE_CAMERA) {
-        updateDevices();
-
-        return m_defaultCameraDevice;
+        const QList<DSVideoDeviceInfo> &devs = DSVideoDeviceControl::availableDevices();
+        if (!devs.isEmpty())
+            return devs.first().first;
     }
 #endif
 
@@ -133,52 +132,29 @@ QByteArray DSServicePlugin::defaultDevice(const QByteArray &service) const
 
 QList<QByteArray> DSServicePlugin::devices(const QByteArray &service) const
 {
+    QList<QByteArray> result;
+
 #ifdef QMEDIA_DIRECTSHOW_CAMERA
     if (service == Q_MEDIASERVICE_CAMERA) {
-        updateDevices();
-
-        return m_cameraDevices;
+        const QList<DSVideoDeviceInfo> &devs = DSVideoDeviceControl::availableDevices();
+        Q_FOREACH (const DSVideoDeviceInfo &info, devs)
+            result.append(info.first);
     }
 #endif
 
-    return QList<QByteArray>();
+    return result;
 }
 
 QString DSServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device)
 {
 #ifdef QMEDIA_DIRECTSHOW_CAMERA
     if (service == Q_MEDIASERVICE_CAMERA) {
-        updateDevices();
-
-        for (int i=0; i<m_cameraDevices.count(); i++)
-            if (m_cameraDevices[i] == device)
-                return m_cameraDescriptions[i];
+        const QList<DSVideoDeviceInfo> &devs = DSVideoDeviceControl::availableDevices();
+        Q_FOREACH (const DSVideoDeviceInfo &info, devs) {
+            if (info.first == device)
+                return info.second;
+        }
     }
 #endif
     return QString();
 }
-
-#ifdef QMEDIA_DIRECTSHOW_CAMERA
-
-void DSServicePlugin::updateDevices() const
-{
-    static QElapsedTimer timer;
-    if (timer.isValid() && timer.elapsed() < 500) // ms
-        return;
-
-    addRefCount();
-
-    m_defaultCameraDevice.clear();
-    DSVideoDeviceControl::enumerateDevices(&m_cameraDevices, &m_cameraDescriptions);
-
-    if (m_cameraDevices.isEmpty()) {
-        qWarning() << "No camera devices found";
-    } else {
-        m_defaultCameraDevice = m_cameraDevices.first();
-    }
-
-    releaseRefCount();
-    timer.restart();
-}
-#endif
-
index 5682534..5cc1788 100644 (file)
@@ -65,15 +65,6 @@ public:
     QByteArray defaultDevice(const QByteArray &service) const;
     QList<QByteArray> devices(const QByteArray &service) const;
     QString deviceDescription(const QByteArray &service, const QByteArray &device);
-
-private:
-#ifdef QMEDIA_DIRECTSHOW_CAMERA
-    void updateDevices() const;
-
-    mutable QByteArray m_defaultCameraDevice;
-    mutable QList<QByteArray> m_cameraDevices;
-    mutable QStringList m_cameraDescriptions;
-#endif
 };
 
 #endif // DSSERVICEPLUGIN_H