Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Python 4-channel rtsp(rtmp) streaming program QThread slow problem
Forum Updated to NodeBB v4.3 + New Features

Python 4-channel rtsp(rtmp) streaming program QThread slow problem

Scheduled Pinned Locked Moved Unsolved Qt for Python
11 Posts 4 Posters 2.5k Views 2 Watching
  • 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.
  • U Offline
    U Offline
    UOUQT
    wrote on last edited by UOUQT
    #1

    It is a 4 channel rtsp(rtmp) streaming program.

    When running with QThread, if you stream 4 at the same time, the speed of the video will slow down and CPU usage will be 100%. I know it's a GIL problem

    1~3 channel is no problem, but only when 4 channel is slow.

    So I want to change to multiprocessing, but I don't know python properly
    Can you change it to multiprocessing?

    I want to speed up a 4 channel cctv program.

    threadMod.py

    from PyQt5.QtCore import QThread, pyqtSignal, Qt
    from PyQt5.QtGui import QImage
    import cv2
    
    class StreamingThread(QThread):
        changePixmap = pyqtSignal(QImage)
    
        def __init__(self):
            super(StreamingThread, self).__init__()
            self.running = True
            self.camUrl = None
            self.Qsize = None
            self.cap = None
    
        def setRtsp(self, camUrl):
            self.camUrl = camUrl
    
        def setSize(self, Qsize):
            self.Qsize = Qsize
    
        def run(self):
            try:
                self.cap = cv2.VideoCapture(self.camUrl)
                if self.cap.isOpened():
                    while self.running:
                        success, frame = self.cap.read()
                        if success:
                            rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                            h, w, ch = rgbImage.shape
                            bytesPerLine = ch * w
                            convertToQtFormat = QImage(rgbImage.data, w, h, bytesPerLine, QImage.Format_RGB888)
                            p = convertToQtFormat.scaled(self.Qsize, Qt.KeepAspectRatio)
                            self.changePixmap.emit(p)
                else:
                    print("RTSP(RTMP) Video Streaming Fail")
                    self.stop()
            except Exception as e:
                print(e)
                self.stop()
    
        def stop(self):
            if self.running:
                self.running = False
                print("Streaming Stop")
            self.quit()
    

    main.py

      def setChannel1(self):
            # Index 0: No Channel
            if self.chComboBox1.currentIndex() == 0:
                self.mStreamingThread1.terminate()
                sched = BackgroundScheduler()
                sched.add_job(self.clearChannel, 'date', run_date=datetime.datetime.now() + datetime.timedelta(seconds=1), args=[self.cctvStreaming1])
                sched.start()
            else:
                ip, url, channel, boxId = self.findUrl(self.chComboBox1)
                if url != '' and channel != '':
                    self.mStreamingThread1.terminate()
                    self.mStreamingThread1.wait(1)
                    self.mStreamingThread1.setRtsp(url)
                    self.mStreamingThread1.setSize(self.cctvStreaming1.size())
                    self.mStreamingThread1.changePixmap.connect(self.setImage1)
                    self.mStreamingThread1.start()
                    self.show()
                    logger.info("Channel1 Streaming Success")
    
        def setChannel2(self):
            # Index 0: No Channel
            if self.chComboBox2.currentIndex() == 0:
                self.mStreamingThread2.terminate()
                sched = BackgroundScheduler()
                sched.add_job(self.clearChannel, 'date', run_date=datetime.datetime.now() + datetime.timedelta(seconds=1), args=[self.cctvStreaming2])
                sched.start()
            else:
                ip, url, channel, boxId = self.findUrl(self.chComboBox2)
                if url != '' and channel != '':
                    self.mStreamingThread2.terminate()
                    self.mStreamingThread2.wait(1)
                    self.mStreamingThread2.setRtsp(url)
                    self.mStreamingThread2.setSize(self.cctvStreaming2.size())
                    self.mStreamingThread2.changePixmap.connect(self.setImage2)
                    self.mStreamingThread2.start()
                    self.show()
                    logger.info("Channel2 Streaming Success")
    
      @pyqtSlot(QImage)
        def setImage1(self, image):
            self.cctvStreaming1.setPixmap(QPixmap.fromImage(image))
    
        @pyqtSlot(QImage)
        def setImage2(self, image):
            self.cctvStreaming2.setPixmap(QPixmap.fromImage(image))
    

    Program Image
    alt text

    jsulmJ jeremy_kJ 2 Replies Last reply
    0
    • U UOUQT

      It is a 4 channel rtsp(rtmp) streaming program.

      When running with QThread, if you stream 4 at the same time, the speed of the video will slow down and CPU usage will be 100%. I know it's a GIL problem

      1~3 channel is no problem, but only when 4 channel is slow.

      So I want to change to multiprocessing, but I don't know python properly
      Can you change it to multiprocessing?

      I want to speed up a 4 channel cctv program.

      threadMod.py

      from PyQt5.QtCore import QThread, pyqtSignal, Qt
      from PyQt5.QtGui import QImage
      import cv2
      
      class StreamingThread(QThread):
          changePixmap = pyqtSignal(QImage)
      
          def __init__(self):
              super(StreamingThread, self).__init__()
              self.running = True
              self.camUrl = None
              self.Qsize = None
              self.cap = None
      
          def setRtsp(self, camUrl):
              self.camUrl = camUrl
      
          def setSize(self, Qsize):
              self.Qsize = Qsize
      
          def run(self):
              try:
                  self.cap = cv2.VideoCapture(self.camUrl)
                  if self.cap.isOpened():
                      while self.running:
                          success, frame = self.cap.read()
                          if success:
                              rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                              h, w, ch = rgbImage.shape
                              bytesPerLine = ch * w
                              convertToQtFormat = QImage(rgbImage.data, w, h, bytesPerLine, QImage.Format_RGB888)
                              p = convertToQtFormat.scaled(self.Qsize, Qt.KeepAspectRatio)
                              self.changePixmap.emit(p)
                  else:
                      print("RTSP(RTMP) Video Streaming Fail")
                      self.stop()
              except Exception as e:
                  print(e)
                  self.stop()
      
          def stop(self):
              if self.running:
                  self.running = False
                  print("Streaming Stop")
              self.quit()
      

      main.py

        def setChannel1(self):
              # Index 0: No Channel
              if self.chComboBox1.currentIndex() == 0:
                  self.mStreamingThread1.terminate()
                  sched = BackgroundScheduler()
                  sched.add_job(self.clearChannel, 'date', run_date=datetime.datetime.now() + datetime.timedelta(seconds=1), args=[self.cctvStreaming1])
                  sched.start()
              else:
                  ip, url, channel, boxId = self.findUrl(self.chComboBox1)
                  if url != '' and channel != '':
                      self.mStreamingThread1.terminate()
                      self.mStreamingThread1.wait(1)
                      self.mStreamingThread1.setRtsp(url)
                      self.mStreamingThread1.setSize(self.cctvStreaming1.size())
                      self.mStreamingThread1.changePixmap.connect(self.setImage1)
                      self.mStreamingThread1.start()
                      self.show()
                      logger.info("Channel1 Streaming Success")
      
          def setChannel2(self):
              # Index 0: No Channel
              if self.chComboBox2.currentIndex() == 0:
                  self.mStreamingThread2.terminate()
                  sched = BackgroundScheduler()
                  sched.add_job(self.clearChannel, 'date', run_date=datetime.datetime.now() + datetime.timedelta(seconds=1), args=[self.cctvStreaming2])
                  sched.start()
              else:
                  ip, url, channel, boxId = self.findUrl(self.chComboBox2)
                  if url != '' and channel != '':
                      self.mStreamingThread2.terminate()
                      self.mStreamingThread2.wait(1)
                      self.mStreamingThread2.setRtsp(url)
                      self.mStreamingThread2.setSize(self.cctvStreaming2.size())
                      self.mStreamingThread2.changePixmap.connect(self.setImage2)
                      self.mStreamingThread2.start()
                      self.show()
                      logger.info("Channel2 Streaming Success")
      
        @pyqtSlot(QImage)
          def setImage1(self, image):
              self.cctvStreaming1.setPixmap(QPixmap.fromImage(image))
      
          @pyqtSlot(QImage)
          def setImage2(self, image):
              self.cctvStreaming2.setPixmap(QPixmap.fromImage(image))
      

      Program Image
      alt text

      jsulmJ Offline
      jsulmJ Offline
      jsulm
      Lifetime Qt Champion
      wrote on last edited by
      #2

      @UOUQT said in Python 4-channel rtsp(rtmp) streaming program QThread slow problem:

      So I want to change to multiprocessing, but I don't know python properly

      Why do you think multi processing will be faster than multi threading?
      If you want to check multi processing then change your code to only use one thread and then start your Python app 4 times.

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      JonBJ U 2 Replies Last reply
      1
      • jsulmJ jsulm

        @UOUQT said in Python 4-channel rtsp(rtmp) streaming program QThread slow problem:

        So I want to change to multiprocessing, but I don't know python properly

        Why do you think multi processing will be faster than multi threading?
        If you want to check multi processing then change your code to only use one thread and then start your Python app 4 times.

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by JonB
        #3

        @jsulm said in Python 4-channel rtsp(rtmp) streaming program QThread slow problem:

        Why do you think multi processing will be faster than multi threading?

        I have no idea whether it is a better approach, but if the OP is right about " I know it's a GIL problem" that could mean the the multi-threaded approach could effectively devolve to single-threaded in Python.

        @UOUQT
        If you want to try a multi-process approach from Qt you can use QProcess, or you can use Python's own process-spawning library. It might be better/the same/worse....

        1~3 channel is no problem, but only when 4 channel is slow.

        Just a thought: do you have a quad-core processor? Maybe you won't be able to run a 4th thread/process simultaneously.

        jeremy_kJ U 2 Replies Last reply
        1
        • U UOUQT

          It is a 4 channel rtsp(rtmp) streaming program.

          When running with QThread, if you stream 4 at the same time, the speed of the video will slow down and CPU usage will be 100%. I know it's a GIL problem

          1~3 channel is no problem, but only when 4 channel is slow.

          So I want to change to multiprocessing, but I don't know python properly
          Can you change it to multiprocessing?

          I want to speed up a 4 channel cctv program.

          threadMod.py

          from PyQt5.QtCore import QThread, pyqtSignal, Qt
          from PyQt5.QtGui import QImage
          import cv2
          
          class StreamingThread(QThread):
              changePixmap = pyqtSignal(QImage)
          
              def __init__(self):
                  super(StreamingThread, self).__init__()
                  self.running = True
                  self.camUrl = None
                  self.Qsize = None
                  self.cap = None
          
              def setRtsp(self, camUrl):
                  self.camUrl = camUrl
          
              def setSize(self, Qsize):
                  self.Qsize = Qsize
          
              def run(self):
                  try:
                      self.cap = cv2.VideoCapture(self.camUrl)
                      if self.cap.isOpened():
                          while self.running:
                              success, frame = self.cap.read()
                              if success:
                                  rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                                  h, w, ch = rgbImage.shape
                                  bytesPerLine = ch * w
                                  convertToQtFormat = QImage(rgbImage.data, w, h, bytesPerLine, QImage.Format_RGB888)
                                  p = convertToQtFormat.scaled(self.Qsize, Qt.KeepAspectRatio)
                                  self.changePixmap.emit(p)
                      else:
                          print("RTSP(RTMP) Video Streaming Fail")
                          self.stop()
                  except Exception as e:
                      print(e)
                      self.stop()
          
              def stop(self):
                  if self.running:
                      self.running = False
                      print("Streaming Stop")
                  self.quit()
          

          main.py

            def setChannel1(self):
                  # Index 0: No Channel
                  if self.chComboBox1.currentIndex() == 0:
                      self.mStreamingThread1.terminate()
                      sched = BackgroundScheduler()
                      sched.add_job(self.clearChannel, 'date', run_date=datetime.datetime.now() + datetime.timedelta(seconds=1), args=[self.cctvStreaming1])
                      sched.start()
                  else:
                      ip, url, channel, boxId = self.findUrl(self.chComboBox1)
                      if url != '' and channel != '':
                          self.mStreamingThread1.terminate()
                          self.mStreamingThread1.wait(1)
                          self.mStreamingThread1.setRtsp(url)
                          self.mStreamingThread1.setSize(self.cctvStreaming1.size())
                          self.mStreamingThread1.changePixmap.connect(self.setImage1)
                          self.mStreamingThread1.start()
                          self.show()
                          logger.info("Channel1 Streaming Success")
          
              def setChannel2(self):
                  # Index 0: No Channel
                  if self.chComboBox2.currentIndex() == 0:
                      self.mStreamingThread2.terminate()
                      sched = BackgroundScheduler()
                      sched.add_job(self.clearChannel, 'date', run_date=datetime.datetime.now() + datetime.timedelta(seconds=1), args=[self.cctvStreaming2])
                      sched.start()
                  else:
                      ip, url, channel, boxId = self.findUrl(self.chComboBox2)
                      if url != '' and channel != '':
                          self.mStreamingThread2.terminate()
                          self.mStreamingThread2.wait(1)
                          self.mStreamingThread2.setRtsp(url)
                          self.mStreamingThread2.setSize(self.cctvStreaming2.size())
                          self.mStreamingThread2.changePixmap.connect(self.setImage2)
                          self.mStreamingThread2.start()
                          self.show()
                          logger.info("Channel2 Streaming Success")
          
            @pyqtSlot(QImage)
              def setImage1(self, image):
                  self.cctvStreaming1.setPixmap(QPixmap.fromImage(image))
          
              @pyqtSlot(QImage)
              def setImage2(self, image):
                  self.cctvStreaming2.setPixmap(QPixmap.fromImage(image))
          

          Program Image
          alt text

          jeremy_kJ Offline
          jeremy_kJ Offline
          jeremy_k
          wrote on last edited by
          #4

          @UOUQT said in Python 4-channel rtsp(rtmp) streaming program QThread slow problem:

          It is a 4 channel rtsp(rtmp) streaming program.

          When running with QThread, if you stream 4 at the same time, the speed of the video will slow down and CPU usage will be 100%. I know it's a GIL problem
          [...]
          threadMod.py

          
          class StreamingThread(QThread):
          
              def run(self):
                  try:
                      self.cap = cv2.VideoCapture(self.camUrl)
                      if self.cap.isOpened():
                          while self.running:
                              success, frame = self.cap.read()
          

          Is VideoCapture.read() blocking while waiting for the next thread? If not, have you looked at how much processing time each channel is consuming, to verify that it isn't possible to process multiple channels in a single thread?

          The OpenCV documentation mentions using grab() and retrieve() instead to handle multiple cameras with tightly synchronized frames.

          main.py

            def setChannel1(self):
          

          setChannel1 and setChannel2 are nearly identical. For the sanity of readers, if not yourself, merge them and use a parameter to select which channel to control. The same goes for the setImage1 and 2.

          Asking a question about code? http://eel.is/iso-c++/testcase/

          1 Reply Last reply
          0
          • JonBJ JonB

            @jsulm said in Python 4-channel rtsp(rtmp) streaming program QThread slow problem:

            Why do you think multi processing will be faster than multi threading?

            I have no idea whether it is a better approach, but if the OP is right about " I know it's a GIL problem" that could mean the the multi-threaded approach could effectively devolve to single-threaded in Python.

            @UOUQT
            If you want to try a multi-process approach from Qt you can use QProcess, or you can use Python's own process-spawning library. It might be better/the same/worse....

            1~3 channel is no problem, but only when 4 channel is slow.

            Just a thought: do you have a quad-core processor? Maybe you won't be able to run a 4th thread/process simultaneously.

            jeremy_kJ Offline
            jeremy_kJ Offline
            jeremy_k
            wrote on last edited by
            #5

            @JonB said in [Python 4-channel rtsp(rtmp) streaming program QThread slow problem]

            @UOUQT
            If you want to try a multi-process approach from Qt you can use QProcess, or you can use Python's own process-spawning library. It might be better/the same/worse....

            multiprocessing is a python package that uses child processes to emulate python threads while escaping the cpython global lock. I haven't done anything significant with it, but presumably this results in side effects that are visible to user code.

            Asking a question about code? http://eel.is/iso-c++/testcase/

            1 Reply Last reply
            0
            • JonBJ JonB

              @jsulm said in Python 4-channel rtsp(rtmp) streaming program QThread slow problem:

              Why do you think multi processing will be faster than multi threading?

              I have no idea whether it is a better approach, but if the OP is right about " I know it's a GIL problem" that could mean the the multi-threaded approach could effectively devolve to single-threaded in Python.

              @UOUQT
              If you want to try a multi-process approach from Qt you can use QProcess, or you can use Python's own process-spawning library. It might be better/the same/worse....

              1~3 channel is no problem, but only when 4 channel is slow.

              Just a thought: do you have a quad-core processor? Maybe you won't be able to run a 4th thread/process simultaneously.

              U Offline
              U Offline
              UOUQT
              wrote on last edited by
              #6

              @JonB Note that in many cases (and virtually all cases where your "expensive operation" is a calculation implemented in Python), multiple threads will not actually run concurrently due to Python's Global Interpreter Lock (GIL).

              JonBJ 1 Reply Last reply
              0
              • U UOUQT

                @JonB Note that in many cases (and virtually all cases where your "expensive operation" is a calculation implemented in Python), multiple threads will not actually run concurrently due to Python's Global Interpreter Lock (GIL).

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by JonB
                #7

                @UOUQT
                Yes, this does not surprise me in Python, which is why I wrote

                but if the OP is right about " I know it's a GIL problem" that could mean the the multi-threaded approach could effectively devolve to single-threaded in Python.

                Not sure why you are addressing this comment to me.

                U 1 Reply Last reply
                0
                • jsulmJ jsulm

                  @UOUQT said in Python 4-channel rtsp(rtmp) streaming program QThread slow problem:

                  So I want to change to multiprocessing, but I don't know python properly

                  Why do you think multi processing will be faster than multi threading?
                  If you want to check multi processing then change your code to only use one thread and then start your Python app 4 times.

                  U Offline
                  U Offline
                  UOUQT
                  wrote on last edited by UOUQT
                  #8
                  This post is deleted!
                  1 Reply Last reply
                  0
                  • JonBJ JonB

                    @UOUQT
                    Yes, this does not surprise me in Python, which is why I wrote

                    but if the OP is right about " I know it's a GIL problem" that could mean the the multi-threaded approach could effectively devolve to single-threaded in Python.

                    Not sure why you are addressing this comment to me.

                    U Offline
                    U Offline
                    UOUQT
                    wrote on last edited by
                    #9

                    @JonB
                    I'm not familiar with python programming language...
                    How do I change it to single-threaded?

                    JonBJ 1 Reply Last reply
                    0
                    • U UOUQT

                      @JonB
                      I'm not familiar with python programming language...
                      How do I change it to single-threaded?

                      JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by
                      #10

                      @UOUQT
                      Remove the threads, or reduce to only using one thread.

                      I did not say running single-threaded was desirable. I said that your comment about Python's GIL might reduce your intended multi-thread performance to single-thread.

                      U 1 Reply Last reply
                      0
                      • JonBJ JonB

                        @UOUQT
                        Remove the threads, or reduce to only using one thread.

                        I did not say running single-threaded was desirable. I said that your comment about Python's GIL might reduce your intended multi-thread performance to single-thread.

                        U Offline
                        U Offline
                        UOUQT
                        wrote on last edited by
                        #11

                        @JonB

                        When running 4 live streams with a single thread, the delay for each channel increased.
                        Probably because of cv2.read 4 times in one thread

                        I don't know if this is the correct coding.

                        1 Reply Last reply
                        0

                        • Login

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