1

I was trying to write a Python program that records current screen in arbitrary fps in OS X, say 60fps.

The fastest way to capture the current screen I found was using subprocess.call(["screencapture", "pic.bmp"]). But it took about 0.16 seconds to take a screenshot and so I couldn't get more than 6 fps by taking screenshots sequentially.

Instead, I tried to use Python's multiprocessing.Process (for the first time) to take screenshots by starting new processes at the interval of 0.0167s to make a 60fps video. I first tried to following code:

from multiprocessing import Process
from subprocess import call
from PIL import Image
import time

def capture(file_name):
    call(["screencapture", file_name])

p1=Process(target=capture, args=("f1",))
p1.start()

p2=Process(target=capture, args=("f2",))
p2.start()

I tested the above code to take 2 pictures of the screen where Google's stopwatch is running. The resulting two pictures showed 0.05 seconds interval which would only be 12 fps at best.

Because there are screen recording programs like Monosnap which supports 60fps, I guess there should be a better way to do this and I'm trying to find how to speed this up. How could I bring down the interval to 0.0167 seconds or less?

Edit1: This is an update to respond to the claim that this is a possible duplicate of Take screenshots **quickly** from python. Actually there is FionaSarah's solution at PyGTK sample from the first link for the original question. But this solution doesn't seem to work with current version of Gdk in gi.repository of PyGObject. FionaSarah uses gtk.gdk.Pixbuf.get_from_drawable which is not found in the current version of Gdk. It seems Gtk.OffscreenWindow can be used instead or one should use use Xlib from this.

Daum Yoon
  • 11
  • 2
  • Are you sure Google stopwatch updates more frequently than 12 fps? – Mad Physicist Jun 21 '18 at 04:07
  • You'd need a library (which you could write yourself) to access some low level buffers instead of starting and stopping a large application every time you want a frame. – Mad Physicist Jun 21 '18 at 04:09
  • Mad Physicist: I'm not sure. But when I also tested with the stopwatch at http://online-stopwatch.chronme.com/, the difference between the times on two pictures was from 0.041s to 0.045s. – Daum Yoon Jun 21 '18 at 04:24
  • Mad Physicist: Actually, using call(["screencapture", file_name]) was an improvement because I was initially using PIL.ImageGrab.grab() which is even slower. I also would like to find a faster way to get access to current screen pixel values but I couldn't find any useful reference. – Daum Yoon Jun 21 '18 at 04:30
  • Possible duplicate of [Take screenshots \*\*quickly\*\* from python](https://stackoverflow.com/q/1276616/2988730) – Mad Physicist Jun 21 '18 at 04:41
  • Googled "fast screen capture Python" – Mad Physicist Jun 21 '18 at 04:50

1 Answers1

1

Have a look à MSS, it is blazing fast and requires no 3rd party modules.

Tiger-222
  • 6,677
  • 3
  • 47
  • 60
  • Thanks! It's taking about 0.2s to take a screenshot with mss as in the link. – Daum Yoon Jun 23 '18 at 10:23
  • Could you share uour code? This is several ways to imrpove depending what do you really want. – Tiger-222 Jun 23 '18 at 11:46
  • Thanks for your interest but I found what I want. I only had to capture certain subregion of the whole screen. By substituting the 7th line of my original code as "call(["screencapture","-x", "-R300,547,300,200", file_name])", it only takes about 0.0023 seconds to take a screenshot of the specified subregion. Typing "man screencapture" shows some manpage of the screencapture. But somehow, just typing "screencapture -p" on terminal tells what are not written in the manpage particularly about -R. – Daum Yoon Jun 24 '18 at 09:04
  • FTR you can capture a region with MSS too. Anyway, glad you found a solution :) – Tiger-222 Jun 24 '18 at 14:44
  • Any chance of making a `sudo apt install MSS` for Debian/Ubuntu distributions? – WinEunuuchs2Unix Jan 11 '20 at 22:04