Search code examples
pythonpython-3.xopencvpyautogui

My Screen Recorder built using OpenCV and PyAutoGUI records only one frame


I am building a Screen Recorder in Python using numpy, OpenCV and PyAutoGUI. I have used tkinter for GUI Purposes. The problem with my screen recorder is that it records only one frame when I click on the Record Screen Button and then the screen gets jammed and I can't do anything. Here is my code so far:

from tkinter import *
import cv2
import numpy as np
import pyautogui

resolution = (1366,768)

Specify video codec:

codec = cv2.VideoWriter_fourcc(*"XVID")

Specify name of Output file:

filename = "Recordings.avi"

Specify frames rate (we can choose any value and experiment with it):

fps = 30.0

Creating a VideoWriter object:

out = cv2.VideoWriter(filename, codec, fps, resolution)

def startRecording():
  
  window.iconify()
  while True:
    img = pyautogui.screenshot()

    # Convert the screenshot to a numpy array
    frame = np.array(img)

    # Convert it from BGR(Blue, Green, Red) to
    # RGB(Red, Green, Blue)
    
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

    # Write it to the output file
      out.write(frame)

def stopRecording():
  cv2.destroyAllWindows()
  out.release()
  window.destroy()



window = Tk()
window.title("Screen Recorder")
window.geometry("400x150")
window.config(bg='pink')

recordButton = Button(window,text="Record(F9)",font=("Bell MT",20),width=20,command=startRecording)
recordButton.pack(pady=(10,0))

stopButton = Button(window,text="Stop(F10)",font=("Bell MT",20),width=20,command=stopRecording)
stopButton.pack(pady=(10,0))

mainloop()

Solution

  • You cannot do a blocking call in a button callback. As you wrote it startRecording will never end and will hence block tkinter mainloop. The recording probably works but your UI becomes unresponsive.

    Your best shot would be to schedule the recording (look for the after method): record one frame every x millisecond.

    Here is a simplified example based on your original code (you need to complete it)

    continueRecording = True # must be declared before stopRecording 
    window = Tk() # must be declared before recordOneFrame
    
    def stopRecording():
        global continueRecording
        continueRecording = False 
    
    def recordOneFrame():
        global continueRecording
        img = pyautogui.screenshot()
    
        # Convert the screenshot to a numpy array
        frame = np.array(img)
    
        # Convert it from BGR(Blue, Green, Red) to
        # RGB(Red, Green, Blue)
        
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    
        # Write it to the output file
        out.write(frame)
        if continueRecording:
            window.after(round(1/25. * 1000),recordOneFrame)
            
    
    def startRecording():
        recordOneFrame()