Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Proper way to record video/live stream with PyQt and openCV



  • 0

    I am trying to record live stream with my PyQt5 GUI. The live stream part is working fine. But the recorded video file is empty.

    Here is the ui file:

    from PyQt5 import QtCore, QtGui, QtWidgets
    
    
    class Ui_Dialog(object):
        def setupUi(self, Dialog):
            Dialog.setObjectName("Dialog")
            Dialog.resize(972, 667)
            self.pushButton = QtWidgets.QPushButton(Dialog)
            self.pushButton.setGeometry(QtCore.QRect(20, 630, 451, 28))
            self.pushButton.setObjectName("pushButton")
            self.pushButton_2 = QtWidgets.QPushButton(Dialog)
            self.pushButton_2.setGeometry(QtCore.QRect(500, 630, 451, 28))
            self.pushButton_2.setObjectName("pushButton_2")
            self.label = QtWidgets.QLabel(Dialog)
            self.label.setGeometry(QtCore.QRect(24, 19, 931, 591))
            self.label.setScaledContents(True)
            self.label.setObjectName("label")
    
            self.retranslateUi(Dialog)
            QtCore.QMetaObject.connectSlotsByName(Dialog)
    
        def retranslateUi(self, Dialog):
            _translate = QtCore.QCoreApplication.translate
            Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
            self.pushButton.setText(_translate("Dialog", "Start Stream"))
            self.pushButton_2.setText(_translate("Dialog", "Record"))
            self.label.setText(_translate("Dialog", "TextLabel"))
    

    And here is my main file:

    from PyQt5.QtCore import QTimer, Qt
    from PyQt5.QtGui import QImage, QPixmap
    from PyQt5 import QtCore, QtGui, QtWidgets
    import sys
    import cv2
    from threading import Thread, Lock
    import time
    from record import *
    
    class WebcamVideoStream :
        def __init__(self, src, width = 640, height = 480) :
            self.stream = cv2.VideoCapture(src)
            self.stream.set(cv2.CAP_PROP_FRAME_WIDTH, width)
            self.stream.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
            self.stream.set(cv2.CAP_PROP_BUFFERSIZE, 5)
            self.FPS = 1/30
            self.FPS_MS = int(self.FPS * 1000)
            (self.grabbed, self.frame) = self.stream.read()
            self.started = False
            self.read_lock = Lock()
    
        def start(self) :
            if self.started :
                return None
            self.started = True
            self.thread = Thread(target=self.update, args=())
            self.thread.daemon = True
            self.thread.start()
            return self
    
        def update(self) :
            while self.started :
                (grabbed, frame) = self.stream.read()
                time.sleep(self.FPS)
                self.read_lock.acquire()
                self.grabbed, self.frame = grabbed, frame
                self.read_lock.release()
    
        def read(self) :
            self.read_lock.acquire()
            frame = self.frame.copy()
            self.read_lock.release()
            return frame
    
        def stop(self) :
            self.started = False
            if self.thread.is_alive():
                self.thread.join()
    
        def __exit__(self, exc_type, exc_value, traceback) :
            self.stream.release()
    
    
    
    class MainWindow(QtWidgets.QDialog, Ui_Dialog):
        def __init__(self, *args, obj=None, **kwargs):
            super(MainWindow, self).__init__(*args, **kwargs)
            self.setupUi(self)
            self.pushButton.clicked.connect(self.start_cam)
            self.pushButton_2.clicked.connect(self.recordImage)
    
    
        def start_cam(self):
            self.capture = WebcamVideoStream(src = 0).start()
            self.timer=QTimer(self)
            self.timer.setTimerType(QtCore.Qt.PreciseTimer)
            self.timer.timeout.connect(self.update_frame)
            self.timer.start(2)
    
        def update_frame(self):
            self.image=self.capture.read()
            self.displayImage(self.image)
    
        def displayImage(self,img):
            qformat=QImage.Format_Indexed8
            if len(img.shape)==3:
                if img.shape[2]==4:
                    qformat=QImage.Format_RGBA8888
                else:
                    qformat=QImage.Format_RGB888
    
            outImage=QImage(img,img.shape[1],img.shape[0],img.strides[0],qformat)
            outImage=outImage.rgbSwapped()
    
            self.label.setPixmap(QPixmap.fromImage(outImage))
            self.label.setScaledContents(True)
            return outImage
    
        def recordImage(self, img):
            self.fourcc = cv2.VideoWriter_fourcc(*'XVID')
            self.out = cv2.VideoWriter('output.avi', self.fourcc, 10, (640,480))
            self.out.write(img)
    
    
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
        mainW = MainWindow()
        mainW.show()
        sys.exit(app.exec_())
    

    Also, while I am using self.recordImage(self.image)in my update_frame function only one frame is recorded as video.

    Looking for a proper way to record the video. Thanks in advance.


  • Lifetime Qt Champion

    Hi,

    Are you not overwriting your file over and over ?
    You should open it once and the write continuously to it until you are done and then close it.



  • @SGaist Thanks for your reply, but i am not overwriting. I am sure about it.


  • Lifetime Qt Champion

    In your code you recreate the writer each time you call recordImage, I do not see why it would in "append mode".



  • @SGaist Okay, I get it. Can you please point me to how to fix it?


  • Lifetime Qt Champion

    Create the writer only once and use it to write each frame.


Log in to reply