0

I'm capturing my screen using OpenCV on windows. It works fine but when I try to play my captured video it plays too fast. i.e. I capture from video for 60 seconds but when I play it OpenCV recorded longer and sped up to fit the additional times content into 60 seconds of video i.e. sped up

import cv2
import numpy as np
import pyautogui

time = 10
# display screen resolution, get it using pyautogui itself
SCREEN_SIZE = tuple(pyautogui.size())
# define the codec
fourcc = cv2.VideoWriter_fourcc(*"XVID")
# frames per second
fps = 30.0
# create the video write object
out = cv2.VideoWriter("output.avi", fourcc, fps, (SCREEN_SIZE))

for i in range(int(time * fps)):
    # make a screenshot
    img = pyautogui.screenshot()
    # convert these pixels to a proper numpy array to work with OpenCV
    frame = np.array(img)
    # convert colors from BGR to RGB
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    # write the frame
    out.write(frame)

# make sure everything is closed when exited
cv2.destroyAllWindows()
out.release()

I tried different fps which did not change much. Please let me know why this happens. Any answers and help welcome.

  • @Aaron Thanks for the advice, but I do not understand how to implement the solution into my script – Digitas Merero Nov 08 '22 at 16:44
  • my bad.. I didn't fully read the code. you make no attempt to wait in-between taking screenshots, so it will take them as fast as it can. You need some way to wait (like `time.sleep`) in-between capturing frames. – Aaron Nov 08 '22 at 16:52

1 Answers1

0

you need to wait in-between taking screen shots. There may be a more ideal solution, but this would probably suffice:

from time import time, sleep
record_time = 10 #don't overwrite the function we just imported
start_time = time()
for i in range(int(record_time * fps)):
    # wait for next frame time
    next_shot = start_time + i/fps
    wait_time = next_shot - time()
    if wait_time > 0:
        sleep(wait_time)
    # make a screenshot
    img = pyautogui.screenshot()
    ...

notes

  • time.time's resolution depends on the OS. Make sure you get a number with fractional seconds. Otherwise you may need to use something like time.perf_counter or time.time_ns.
  • This cannot make the loop run faster, only slower. If you can't acquire frames fast enough, the recording will last longer than record_time seconds, and the playback will seem "sped up". the only way to fix that is to find a faster way to acquire screenshots (like lowering resolution perhaps?).
Aaron
  • 10,133
  • 1
  • 24
  • 40
  • Thank you! This is very helpful, regarding the second issue, would you know how to make it forcefully finish the recording after record_time? This could help prevent longer recording times – Digitas Merero Nov 08 '22 at 17:40
  • `if time() > start_time + record_time: break` – Aaron Nov 08 '22 at 18:29
  • @DigitasMerero a discussion on faster screencaps: https://stackoverflow.com/questions/3586046/fastest-way-to-take-a-screenshot-with-python-on-windows – Aaron Nov 08 '22 at 18:59
  • The absolute fastest performance would come from accessing the gpu's capture api directly, but that's way harder... (like [this](https://developer.nvidia.com/capture-sdk)) – Aaron Nov 08 '22 at 19:00