Video speed is very fast

I am trying to make an opensource screen recorder app and this is the code i have written till now

'''Import All the stuff below'''

from tkinter import *
from PIL import ImageGrab
import numpy as np
import cv2
from datetime import datetime
import time

'''Import All the stuff above'''


# Tk() class's instance below
app = Tk()
# Tk() class's instance above



# Vid Name
date_and_time = datetime.now().strftime('%Y-%m-%d %H-%M-%S')
vid_name = f'Simple Recorder {date_and_time}.mp4'
# Vid Name



# Getting screen size below
width = app.winfo_screenwidth()
height = app.winfo_screenheight()
#getting screen size above



vid_writer = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
captured_vid = cv2.VideoWriter(vid_name, vid_writer, 30.0, (width, height))

while 1:
	img = ImageGrab.grab(bbox = (0, 0, width, height))
	img_np = np.array(img)
	img_final = cv2.cvtColor(img_np, cv2.COLOR_BGR2RGB)
	cv2.imshow('Simple Recorder', img_final)
	cv2.waitKey(33)
	captured_vid.write(img_final)


	if cv2.getWindowProperty('Simple Recorder', cv2.WND_PROP_VISIBLE) < 1:
		break


The problem is whenever i run the recorded .mp4 file it is fastforwarded and i have no idea how to handle this problem

can any one help me??
ThankYou in Advance!!!

check how many frames per second you actually capture and write.

Code

VideoWriter(..., 30.0)

doesn’t mean that it will create correct video with 30 FPS.

It only inform video that it has to display 30 frames every second. But if you will generate and write 15 images every second then it will display them in 0.5 second (instead of 1 second) - so it will display it faster. If you will generate and write 60 images every seconds then it will display them in 2 seconds (instead of 1 second) - so it will display it slower.


You set

 waitKey(33) 

so it should run loop 30 times in every second

1s/33ms = 1000ms/33ms = ~30 FPS 

but code needs also time to run ImageGrab, convert it to numpy array, etc.
On my computer it takes ~60-100ms so I can get only 14-15 images every second (if I set waitKey(1)).


This code measures time and display how many FPS you should use in VideoWriter

Because .mp4 doesn’t work on my computer so I use .avi

import tkinter
from datetime import datetime
from PIL import ImageGrab
import numpy as np
import cv2
import time

#video_name = datetime.now().strftime('Simple Recorder %Y-%m-%d %H-%M-%S.mp4')
video_name = datetime.now().strftime('Simple Recorder %Y-%m-%d %H-%M-%S.avi')

# getting screen size
app = tkinter.Tk()
#app.iconify()  # minimize window to icon on taskbar
#app.withdraw()  # hide window without icon on taskbar
width  = app.winfo_screenwidth()   # //4
height = app.winfo_screenheight()  # //2
app.destroy()

#video_format = cv2.VideoWriter_fourcc(*'mp4v')  # .mp4
video_format = cv2.VideoWriter_fourcc(*'MP42')  # .avi 
video_writer = cv2.VideoWriter(video_name, video_format, 15.0, (width, height))

while True:
    start = time.time()
    
    img = ImageGrab.grab(bbox=(0, 0, width, height))
    img = np.array(img)
    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
    cv2.imshow('Simple Recorder', img)
    
    end = time.time()
    diff = (end-start)*1000
    print('time: {:6.2f} ms | {:5.2f} FPS'.format(diff, 1000/diff ))
    
    cv2.waitKey(1)
    
    video_writer.write(img)

    if cv2.getWindowProperty('Simple Recorder', cv2.WND_PROP_VISIBLE) < 1:
        break

Better method would be to run ImageGrab, numpy.array, cvtColor in separated thread and later in while-loop use cv2.waitKey(33) to control how often to write image to file. If there will be no new image then it will write previous image but at least it will write 30 frames every second.

Somewhere on PyImageSearch was even example how to use threads to get ~120FPS from WebCam.

Maybe later I create version with threads

Thankyou for your support,

I manage to get the fps i want (because of you)

but a new problem has came!!

i completed the code part of the software and now when i convert .py file to linux executable i get the executable with no errors
but
whenever i hit the record button on the gui i get an error saying somthing like this

qt.qpa.plugin: Could not find the Qt platform plugin "xcb" in "/tmp/_MEIdKXjK0/cv2/qt/plugins"
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.

Aborted (core dumped)

what is this about??

we might have no idea. a qt, not an opencv problem ;(

Using print(cv2.__file__) you can find folder with source code and there should be subfolder plugins/platforms/ with libqxcb.so which you may need to add to config file when you convert to executable.

On my Linux Mint it is

/usr/local/lib/python3.8/dist-packages/cv2/qt/plugins/platforms/libqxcb.so