Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Detect when webcam is unplugged
QtWS25 Last Chance

Detect when webcam is unplugged

Scheduled Pinned Locked Moved Unsolved General and Desktop
13 Posts 7 Posters 4.5k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Chris HennesC Offline
    Chris HennesC Offline
    Chris Hennes
    wrote on last edited by Chris Hennes
    #1

    My app has a QCameraViewfinder that shows the output from a webcam. When the webcam is unplugged, it just shows the last frame it got. In an ideal world I'd like to detect this situation and switch to showing the error I show when the camera can't be connected to on startup. Is there a good way of detecting the "camera unplugged" condition?

    Chris Hennes, Pioneer Library System

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      Just a quick idea but the QCamera::status property might be what you are looking for.

      Hope it helps

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0
      • Chris HennesC Offline
        Chris HennesC Offline
        Chris Hennes
        wrote on last edited by Chris Hennes
        #3

        Thanks for the suggestion. Unfortunately, when a webcam is simply unplugged it never changes status or state (both things that there are signals for). So my solution for now is polling. I know, I know... but I simply could not figure out any other way. So I made a QThread subclass that when constructed takes a QCameraInfo object and stores it off. When you fire off that thread its run() function loops and scans for available cameras. It looks through the cameras and if it finds the one it was constructed with it does nothing. If not, it fires off a signal. Here's the code (suggestions welcome):

        void CameraMonitor::run()
        {
            qDebug() << "Starting a new check thread";
            while (true) {
                if (QThread::currentThread()->isInterruptionRequested()) {
                    return;
                }
                auto cameras = QCameraInfo::availableCameras();
                bool found (false);
                for (auto camera: cameras) {
                    if (camera == _camera) {
                        found = true;
                    }
                }
                if (!found) {
                    emit cameraLost();
                    return;
                }
        
                if (QThread::currentThread()->isInterruptionRequested()) {
                    return;
                }
                sleep(1);
            }
        }
        

        Chris Hennes, Pioneer Library System

        ? kshegunovK 2 Replies Last reply
        0
        • Chris HennesC Chris Hennes

          Thanks for the suggestion. Unfortunately, when a webcam is simply unplugged it never changes status or state (both things that there are signals for). So my solution for now is polling. I know, I know... but I simply could not figure out any other way. So I made a QThread subclass that when constructed takes a QCameraInfo object and stores it off. When you fire off that thread its run() function loops and scans for available cameras. It looks through the cameras and if it finds the one it was constructed with it does nothing. If not, it fires off a signal. Here's the code (suggestions welcome):

          void CameraMonitor::run()
          {
              qDebug() << "Starting a new check thread";
              while (true) {
                  if (QThread::currentThread()->isInterruptionRequested()) {
                      return;
                  }
                  auto cameras = QCameraInfo::availableCameras();
                  bool found (false);
                  for (auto camera: cameras) {
                      if (camera == _camera) {
                          found = true;
                      }
                  }
                  if (!found) {
                      emit cameraLost();
                      return;
                  }
          
                  if (QThread::currentThread()->isInterruptionRequested()) {
                      return;
                  }
                  sleep(1);
              }
          }
          
          ? Offline
          ? Offline
          A Former User
          wrote on last edited by A Former User
          #4

          @Chris-Hennes Actually I think polling is the only option you have. Neither statusChanged, stateChanged or availabilityChanged is triggered when a camera is unplugged (at least on Windows with the camera I tested), neither in the C++ or QML API. As even the almighty OpenCV doesn't seem to have an API for "camera unplugged", I assume it's really a limitation of the underlying OS-subsystems.

          1 Reply Last reply
          1
          • J.HilkJ Offline
            J.HilkJ Offline
            J.Hilk
            Moderators
            wrote on last edited by
            #5

            @Chris-Hennes @Wieland

            I haven't tested it my self, but QCamera inherits from QMediaObject and therefore should have access to the the Signal void QMediaObject::availabilityChanged(QMultimedia::AvailabilityStatus availability)

            this should emit a Signal when the camera becomes unavailable!?


            Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


            Q: What's that?
            A: It's blue light.
            Q: What does it do?
            A: It turns blue.

            Chris HennesC 1 Reply Last reply
            0
            • J.HilkJ J.Hilk

              @Chris-Hennes @Wieland

              I haven't tested it my self, but QCamera inherits from QMediaObject and therefore should have access to the the Signal void QMediaObject::availabilityChanged(QMultimedia::AvailabilityStatus availability)

              this should emit a Signal when the camera becomes unavailable!?

              Chris HennesC Offline
              Chris HennesC Offline
              Chris Hennes
              wrote on last edited by Chris Hennes
              #6

              @J.Hilk Unfortunately, although it certainly seems like it should emit that signal, it does not (at least in Windows). Absolutely nothing that I could find emits a signal when I unplug the webcam from my Win10 PC. The good news is that the polling solution I posted above works very well, and by running it in its own thread doesn't impact the performance of my program. The call to QCameraInfo::availableCameras() takes over a half second on my machine!

              Chris Hennes, Pioneer Library System

              1 Reply Last reply
              0
              • Chris HennesC Chris Hennes

                Thanks for the suggestion. Unfortunately, when a webcam is simply unplugged it never changes status or state (both things that there are signals for). So my solution for now is polling. I know, I know... but I simply could not figure out any other way. So I made a QThread subclass that when constructed takes a QCameraInfo object and stores it off. When you fire off that thread its run() function loops and scans for available cameras. It looks through the cameras and if it finds the one it was constructed with it does nothing. If not, it fires off a signal. Here's the code (suggestions welcome):

                void CameraMonitor::run()
                {
                    qDebug() << "Starting a new check thread";
                    while (true) {
                        if (QThread::currentThread()->isInterruptionRequested()) {
                            return;
                        }
                        auto cameras = QCameraInfo::availableCameras();
                        bool found (false);
                        for (auto camera: cameras) {
                            if (camera == _camera) {
                                found = true;
                            }
                        }
                        if (!found) {
                            emit cameraLost();
                            return;
                        }
                
                        if (QThread::currentThread()->isInterruptionRequested()) {
                            return;
                        }
                        sleep(1);
                    }
                }
                
                kshegunovK Offline
                kshegunovK Offline
                kshegunov
                Moderators
                wrote on last edited by kshegunov
                #7

                @Chris-Hennes said in Detect when webcam is unplugged:

                I know, I know... but I simply could not figure out any other way.

                I would suggest a more responsive polling method, however. Consider this:

                void CameraMonitor::interrupt()
                {
                    requestInterruption();
                    threadWait.release();
                }
                
                void CameraMonitor::run()
                {
                    qDebug() << "Starting a new check thread";
                    while (!isInterruptionRequested()) {
                        auto cameras = QCameraInfo::availableCameras();
                        bool found = false;
                        for (auto camera : cameras)  {
                            if (camera == _camera) //< Beware!! This may be a race condition (QCameraInfo *might* not be reentrant)!! You should be careful about it.
                                found = true;
                        }
                        if (!found) {
                            emit cameraLost();
                            return;
                        }
                
                        threadWait.tryAcquire(1, 1000); // Wait 1 second or until we are flagged that we should exit (i.e. interrupt() was called).
                    }
                }
                

                Where threadWait is a default initialized QSemaphore instance. Also take note on my comment about the way you compare the camera info objects, it may be dangerous ...

                Read and abide by the Qt Code of Conduct

                1 Reply Last reply
                2
                • Chris HennesC Offline
                  Chris HennesC Offline
                  Chris Hennes
                  wrote on last edited by
                  #8

                  Thanks, using the QSemaphore is a good idea. I'm not sure how to address your concern about QCameraInfo. In my implementation _camera is set before the thread is started, and then only changes in response to the cameraLost() signal (which is emitted and then ends the thread). My thinking was that this was enough to ensure I was avoiding a race condition. Is there a corner case I am missing, or is a changing _camera not what you were concerned about?

                  Chris Hennes, Pioneer Library System

                  kshegunovK 1 Reply Last reply
                  0
                  • Chris HennesC Chris Hennes

                    Thanks, using the QSemaphore is a good idea. I'm not sure how to address your concern about QCameraInfo. In my implementation _camera is set before the thread is started, and then only changes in response to the cameraLost() signal (which is emitted and then ends the thread). My thinking was that this was enough to ensure I was avoiding a race condition. Is there a corner case I am missing, or is a changing _camera not what you were concerned about?

                    kshegunovK Offline
                    kshegunovK Offline
                    kshegunov
                    Moderators
                    wrote on last edited by kshegunov
                    #9

                    @Chris-Hennes said in Detect when webcam is unplugged:

                    In my implementation _camera is set before the thread is started, and then only changes in response to the cameraLost() signal (which is emitted and then ends the thread). My thinking was that this was enough to ensure I was avoiding a race condition.

                    If CameraInfo is reentrant it is. However, it's not stated in the QtMultimedia docs, so any calls into that module (i.e. calling some function like QCameraInfo::availableCameras() from a different thread) while your polling thread is running may be a race condition. To make matter worse the last is not even a requirement as the module might queue some async operation behind the scenes, which might also induce a race condition (e.g. modifying an internal static member from the main thread, while you hold a camera info instance which depends on that resource). And finally using a non-reentrant class/function makes the user code non-reentrant too, which is the worst.

                    @Chris-Hennes said in Detect when webcam is unplugged:

                    Is there a corner case I am missing, or is a changing _camera not what you were concerned about?

                    I'm concerned about the module pulling the rug from under your feet, so to speak. What you should do to be sure is to take a look at the module's source and make certain there are no common statics between the classes that break reentrancy or bring the question of whether the classes are reentrant to the mailing list. I strongly suspect the QMediaObject implementations are not reentrant however, so don't hold your breath ...

                    Read and abide by the Qt Code of Conduct

                    1 Reply Last reply
                    0
                    • Chris HennesC Offline
                      Chris HennesC Offline
                      Chris Hennes
                      wrote on last edited by
                      #10

                      The QCameraInfo class itself is basically trivial, it's just a bit of storage and and accessor, with no static variables. It's that static member function that introduces the complication: in particular I have no idea what QMediaServiceProvider might be doing in the call to provider->devices(service); (qcamerainfo.cpp:248). I don't see a clear path forward from here. That call is slow -- for usability it's got to be in its own thread. It seems like overkill to write an entire wrapper class for the QCameraInfo functionality, but I don't see how short of doing that I can guarantee thread safety.

                      Chris Hennes, Pioneer Library System

                      kshegunovK 1 Reply Last reply
                      0
                      • Chris HennesC Chris Hennes

                        The QCameraInfo class itself is basically trivial, it's just a bit of storage and and accessor, with no static variables. It's that static member function that introduces the complication: in particular I have no idea what QMediaServiceProvider might be doing in the call to provider->devices(service); (qcamerainfo.cpp:248). I don't see a clear path forward from here. That call is slow -- for usability it's got to be in its own thread. It seems like overkill to write an entire wrapper class for the QCameraInfo functionality, but I don't see how short of doing that I can guarantee thread safety.

                        kshegunovK Offline
                        kshegunovK Offline
                        kshegunov
                        Moderators
                        wrote on last edited by
                        #11

                        @Chris-Hennes said in Detect when webcam is unplugged:

                        The QCameraInfo class itself is basically trivial, it's just a bit of storage and and accessor, with no static variables.

                        Then it is probably okay.

                        It's that static member function that introduces the complication: in particular I have no idea what QMediaServiceProvider might be doing in the call to provider->devices(service); (qcamerainfo.cpp:248). I don't see a clear path forward from here.

                        I advise to bring it to the mailing list. There you could get thoughts from the developers of the module and perhaps a better/improved solution. I currently don't have the time to dig into the module, but I suspect that provider->devices(service); is listing the devices through a common system resource, which implies it isn't thread-safe.

                        Read and abide by the Qt Code of Conduct

                        1 Reply Last reply
                        0
                        • M Offline
                          M Offline
                          mayamail
                          wrote on last edited by
                          #12

                          You can use the statusChanged signal of QCamera to detect when the camera is disconnected. When the status changes to QCamera::UnavailableStatus, you can switch to displaying the error message indicating the camera can't be connected. Here's a brief example of how you can implement it:

                          camera = QCamera()
                          camera.setViewfinder(viewfinder)  # Assuming viewfinder is your QCameraViewfinder
                          
                          def handle_camera_status(status):
                              if status == QCamera.UnavailableStatus:
                                  # Switch to displaying error message
                                  display_error_message()
                          
                          camera.statusChanged.connect(handle_camera_status)
                          

                          I have test and take help from Chat GPT 4 and it's was working for me and hope it will also work for you.

                          Best..
                          Maya (author of webcammictest.io)

                          JoeCFDJ 1 Reply Last reply
                          0
                          • M mayamail

                            You can use the statusChanged signal of QCamera to detect when the camera is disconnected. When the status changes to QCamera::UnavailableStatus, you can switch to displaying the error message indicating the camera can't be connected. Here's a brief example of how you can implement it:

                            camera = QCamera()
                            camera.setViewfinder(viewfinder)  # Assuming viewfinder is your QCameraViewfinder
                            
                            def handle_camera_status(status):
                                if status == QCamera.UnavailableStatus:
                                    # Switch to displaying error message
                                    display_error_message()
                            
                            camera.statusChanged.connect(handle_camera_status)
                            

                            I have test and take help from Chat GPT 4 and it's was working for me and hope it will also work for you.

                            Best..
                            Maya (author of webcammictest.io)

                            JoeCFDJ Offline
                            JoeCFDJ Offline
                            JoeCFD
                            wrote on last edited by JoeCFD
                            #13

                            @mayamail Works? Nice! What is your Qt version? And the class QCameraViewfinder does not exist any more in Qt6.

                            1 Reply Last reply
                            0
                            • JoeCFDJ JoeCFD referenced this topic on

                            • Login

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • Users
                            • Groups
                            • Search
                            • Get Qt Extensions
                            • Unsolved