Created
August 31, 2022 16:26
-
-
Save nitori/a2d0029c9f2795b995b29ae57a23fff1 to your computer and use it in GitHub Desktop.
Uses ffmpeg to grab screen and outputs in Surface on pygame
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import annotations | |
from threading import Thread, Event | |
from queue import Queue | |
import subprocess | |
import pygame | |
MONITORS = { | |
'left': (-1920, 0, 1920, 1080), | |
'middle': (0, 0, 2560, 1440), # presumably main monitor, hence offset is (0, 0) | |
'right': (2560, 0, 1920, 1080), | |
} | |
def ffmpeg_thread(monitor: str, q: Queue, stop_ev: Event, w: int, h: int) -> None: | |
sx, sy, sw, sh = MONITORS[monitor] | |
proc = subprocess.Popen([ | |
'ffmpeg', | |
'-hide_banner', | |
'-loglevel', 'warning', | |
'-f', 'gdigrab', | |
'-probesize', '42M', | |
'-framerate', '15', | |
'-offset_x', f'{sx}', | |
'-offset_y', f'{sy}', | |
'-video_size', f'{sw}x{sh}', | |
'-show_region', '1', | |
'-i', 'desktop', | |
'-vf', f'scale={w}:{h}', | |
'-f', 'rawvideo', | |
'-pix_fmt', 'rgb24', | |
'-vcodec', 'rawvideo', | |
'-', | |
], stdout=subprocess.PIPE) | |
buf = b'' | |
framesize = w * h * 3 | |
while not stop_ev.is_set(): | |
chunk = proc.stdout.read(framesize) | |
if not chunk: | |
break | |
buf += chunk | |
while len(buf) >= framesize: | |
q.put(buf[:framesize]) | |
buf = buf[framesize:] | |
proc.terminate() | |
proc.wait() | |
def main(): | |
grabwh = 854, 480 | |
ffmpeg_q = Queue() | |
ffmpeg_ev = Event() | |
ffmpeg_t = Thread(target=ffmpeg_thread, args=('left', ffmpeg_q, ffmpeg_ev, *grabwh)) | |
ffmpeg_t.start() | |
pygame.init() | |
pw, ph = 1280, 720 | |
screen = pygame.display.set_mode((pw, ph)) | |
screen.fill((0, 0, 0)) | |
clock = pygame.time.Clock() | |
last_frame = None | |
vx = 3 | |
vy = 2 | |
sx = 0 | |
sy = 0 | |
while True: | |
for event in pygame.event.get(): | |
if event.type == pygame.QUIT: | |
ffmpeg_ev.set() | |
ffmpeg_t.join() | |
return | |
frame = last_frame | |
while not ffmpeg_q.empty(): | |
frame = ffmpeg_q.get() | |
if frame is not None: | |
last_frame = frame | |
surface = pygame.image.frombuffer(frame, grabwh, 'RGB') | |
sx += vx | |
sy += vy | |
if sx < 0 or sx > pw - grabwh[0]: | |
vx = -vx | |
if sy < 0 or sy > ph - grabwh[1]: | |
vy = -vy | |
screen.fill((0, 0, 0)) | |
screen.blit(surface, (sx, sy)) | |
pygame.display.flip() | |
clock.tick(60) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment