-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Recordings are sped up significantly #3
Comments
Just replicated on Windows 10, with Python 3.8.3. Output seems to be discarding frames and/or dropping frames significantly? |
I think i figured out part of the problem, it seems to be related to the time it takes to call I added
Then my video which should be 10 sec went from 1 sec to 6 sec Also to help diagnose the issue I added this print statement in
My 10 sec video at 10 fps should result in 100 frames, before my change above I got 37 frames, after the change i got 68 frames, still not 100 but closer Python 3.10.12 on Ubuntu 22.04 |
I am sorry that I am very late in responding to this issue. I debugged this a while back, and my conclusion aligns with what @damies13 found out. The problem is that there are not enough screenshots generated during the recording phase as OpenCV expects. For example, with 10fps recording for 10 seconds, there should be 100 frames but we always get less than that. OpenCV writes the video at 10fps resulting in less duration. The approach pyscreenrec uses to record the screen, i.e., screenshotting, sleeping, and then combining the frames into a video is naive. This work is done in a separate thread to ensure that the main thread isn't blocked. Since Python threads don't run in parallel, this thread will not get all the time it needs. Using processes instead of threads won't solve this either, since processes would be subject to OS context switches too (a hypothesis, there would still be a difference tho). Ideally, it should use the OS-specific screen capture APIs, which is a lot of work. |
My approach of subtracting the execution time from the sleep, while not perfect at least improved it, so until you find an OS-specific screen capture API library, this at least would be an improvement, though my code was pretty rough so would need to be cleaned up before publishing, though I'm sure you got the idea and can do that. |
I'd try experimenting with that. Thanks for your active participation in resolving this issue. |
A new release has been published incorporating the fix suggested by @damies13. I'll keep this issue open though, to encourage further discussion on this issue. |
I attempted to locate the specific source of the delay and received the following output:
As a result, I tried adding frame scaling during capture to attempt to reduce write pressure: def _start_recording(self) -> None:
with mss.mss() as sct:
if self.__running.value != 0:
warn("Screen recording is already running.", ScreenRecordingInProgress)
else:
self.__running.value = 1
while self.__running.value != 0:
st_start = time.perf_counter()
img = sct.grab(self.mon)
frame = np.array(img)
# Scale image dimensions
scale_percent = 50 # Scaling percentage, adjust as needed
width = int(frame.shape[1] * scale_percent / 100)
height = int(frame.shape[0] * scale_percent / 100)
dim = (width, height)
resized_frame = cv2.resize(frame, dim, interpolation=cv2.INTER_AREA)
# Put the scaled frame into the queue
self.queue.put(resized_frame)
st_total = time.perf_counter() - st_start
time.sleep(max(0, 1 / self.fps - st_total)) This approach significantly reduced the write pressure, but since this solution affects the target video quality, I haven't submitted a PR for the code modification yet. I'm currently working on quality restoration processing that minimizes the impact as much as possible. |
Sounds great, I'll be looking forward to another PR :). |
@StepaniaH's comment is really interesting, most of the time is taken in write, I wonder if there's a library that can be used for buffered writing in a separate thread? If so it might allow a frame rate of around 12fps (enough for smooth motion, 12 fps is what Disney's original mick mouse cartoons were) |
Maybe python can not achieve enough speed to record a video like 30 fps or even 60 fps, cause its threads don't run in parallel? I do NOT sure, I just a rookie of the python. 🤔 |
Python threads do not run in parallel. The Python interpreter switches between the threads, as per the docs:
I tried replacing threads with processes for v0.6, but processes are much more complex—for example, they maintain their memory. Communication between processes is also possible only with pickle-able objects. Maybe I should try exploring this option again now that the library code has been simplified. I like the idea of a buffered writer tho - it might reduce the write time. |
Describe the bug
When using the example code, the output .mp4 has a much faster speed than the recording length. For example, I use a 20s sleep to invoke the stop_recording() method, but the output file is 4s with everything sped up. Using 60fps, and default fps. Using standard file name. Not sure what's causing this behavior.
To Reproduce
Run the following chunk
Expected behavior
A 20s mp4 in my fullpath directory. Actual behavior: 1s.
Desktop (please complete the following information):
Additional context
Would be happy to contribute a fix, just not sure why it is doing this.
The text was updated successfully, but these errors were encountered: