BoboTiG / python-mss

An ultra fast cross-platform multiple screenshots module in pure Python using ctypes.
https://pypi.org/project/mss/
MIT License
1.01k stars 93 forks source link

How would I save the frames to a video file? #217

Closed Maxhem2 closed 1 year ago

Maxhem2 commented 1 year ago

General information:

Full message

Rather a question would be nice if I got some help 
laerson-hammes commented 1 year ago

You can use OpenCV with PILL for make this...

I have a code, simple, but for some reason the recording speed is too high

from datetime import datetime
from PIL import Image
from mss import mss
import numpy as np
import threading
import pyautogui
import keyboard
import win32api
import cv2

class Monitor:

    def __init__(self) -> None:
        self.device = win32api.EnumDisplayDevices()

    def get_refresh_rate(self):
        settings = win32api.EnumDisplaySettings(self.device.DeviceName, -1)
        return getattr(settings, 'DisplayFrequency')

    def get_screen_size(self) -> tuple:
        return tuple(pyautogui.size())

    def get_frame(self):
        x, y = self.get_screen_size()
        conf = {
            'top': 0,
            'left': 0,
            'width': x,
            'height': y
        }
        with mss(with_cursor=True) as screen:
            return screen.grab(conf)
        # return cv2.cvtColor(
        #     np.array(pyautogui.screenshot()),
        #     cv2.COLOR_RGB2BGR
        # )

class CaptureScreen(Monitor):

    def __init__(self) -> None:
        super().__init__()
        self.codec = cv2.VideoWriter_fourcc(*"XVID")
        self.filename = str(datetime.now()).split(".")[0].replace(" ", "-").replace(":", "-")
        self.stop_recording = [0]
        self.screen_size = self.get_screen_size()

    def _capture(self):
        video = cv2.VideoWriter(
            f"{self.filename}.avi",
            self.codec,
            self.get_refresh_rate(),
            self.screen_size
        )
        while self.stop_recording[0] != 1:
            image = self.get_frame()
            img = Image.frombytes("RGB", image.size, image.bgra, "raw", "BGRX")
            video.write(
                np.array(img)
            )

        print("ending recording")
        video.release()
        cv2.destroyAllWindows()

    def capture(self):
        capture = threading.Thread(target=self._capture)
        capture.start()

if __name__ == "__main__":
    capture = CaptureScreen()
    capture.capture()
    while True:
        if keyboard.is_pressed("esc"):
            capture.stop_recording[0] = 1
            break

In the get_frame method, you can see an other example (commented), but, using PyAutoGUI screenshot...

If you need learn more about, visit PILL documentation

Maxhem2 commented 1 year ago

Thanks, really appreciate your help