2

I'm currently using the Robot classes in Java to record the screen. However, it does not achieve the minimum of 30 frames per second. I'm not re-creating objects, and am being as efficient as I can, but I only average around 15 frames per second. Robot is simply not cutting it.

What can I use to capture the screen? I've tried Xuggle, but I can't seem to get that to capture fast enough either.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Rainfur
  • 43
  • 2
  • 9
  • 1
    FFmpeg supports [x11grab video input](http://ffmpeg.org/ffmpeg.html#x11grab) that works fast, but only for the X Window System. If that is satisfactory, the `FFmpegFrameGrabber` class of [JavaCV](http://code.google.com/p/javacv/) can get you the images. Let me know if you want some sample code as answer – Samuel Audet Dec 08 '12 at 02:49
  • Yeah, it might help for it. I'm not sure how I'd do that... – Rainfur Dec 08 '12 at 04:17
  • I wanted to say, do you care about Windows and Mac OS X, for example, or is X11 sufficient? – Samuel Audet Dec 08 '12 at 09:02
  • I'd like it be windows, if you know how to exactly. Could you also show me the X11 method as well? – Rainfur Dec 08 '12 at 16:00
  • Robot is probably too slow for that unless it's been reimplemented in the latest JDK. – BillRobertson42 Dec 09 '12 at 02:58
  • Yes, hence why I'm waiting for Samual Audet's method. – Rainfur Dec 09 '12 at 03:51

2 Answers2

6

For operating systems following the X11 standard (Linux, FreeBSD, Solaris, etc.), we can do it this way via JavaCV and FFmpeg:

import com.googlecode.javacv.*;

public class ScreenGrabber {
    public static void main(String[] args) throws Exception {
        int x = 0, y = 0, w = 1024, h = 768; // specify the region of screen to grab
        FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(":0.0+" + x + "," + y);
        grabber.setFormat("x11grab");
        grabber.setImageWidth(w);
        grabber.setImageHeight(h);
        grabber.start();

        CanvasFrame frame = new CanvasFrame("Screen Capture");
        while (frame.isVisible()) {
            frame.showImage(grabber.grab());
        }
        frame.dispose();
        grabber.stop();
    }
}

I don't know about Windows or Mac OS X, but I suspect we would need to access native APIs directly. Nevertheless, JavaCPP could help with that.

Samuel Audet
  • 4,964
  • 1
  • 26
  • 33
  • 2
    According to https://trac.ffmpeg.org/wiki/Capture/Desktop you should be able to use the same API just using a different `device` (`dshow` instead of `x11grab` for Windows and `avfoundation` for OSX) – Roberto Andrade Mar 04 '15 at 20:59
5

Build on @Samuel's answer, according to the official ffmpeg documentation you should be able to keep it pretty cross platform if you make the file parameter passed to the FFmpegFrameGrabber (which is really an input parameter that gets passed down as the -i option to ffmpeg) adhere to the different formats each device expects.

ie:

for Windows: dshow expects -i video="screen-capture-recorder"

for OSX: avfoundation expects -i "<screen device index>:"

and for Linux: x11grab expects -i :<display id>+<x>,<y>.

So just passing those values (arguments to -i) to the constructor and setting the format (via setFormat) accordingly should do the trick:

Examples:

for Windows:

new FFmpegFrameGrabber("video=\"screen-capture-recorder\"")
    .setFormat("dshow");

for OSX:

new FFmpegFrameGrabber("\"<screen device index>:\"")
    .setFormat("avfoundation");

for Linux:

new FFmpegFrameGrabber(":<display id>+<x>,<y>")
    .setFormat("x11grab");

PS: Haven't tested this fully so not sure if the quotes are actually necessary.

Roberto Andrade
  • 1,793
  • 1
  • 21
  • 27
  • 1
    can you elaborate on how to set the options for windows a bit more? I'm trying to find out which options need to go into the format and which go into the constructor. Thank you. – Doctor Parameter Jul 24 '15 at 20:54
  • Edited my answer and added a few examples showing the parameters being passed. – Roberto Andrade Jul 25 '15 at 12:02
  • 2
    For Windows specifically you could also use `gdigrab` as a format and pass the input/file parameter and options accordingly. See http://ffmpeg.org/ffmpeg-devices.html for more. – Roberto Andrade Jul 25 '15 at 12:07
  • I'm getting the following error: org.bytedeco.javacv.FrameGrabber$Exception: avformat_open_input() error -5: Could not open input "video='screen-capture-recorder'". (Has setFormat() been called?). I'm using the following code: FFmpegFrameGrabber retVal = new FFmpegFrameGrabber("video='screen-capture-recorder'"); retVal.setFormat("gdigrab"); The error occurs when I call the start method of the return object. – Doctor Parameter Jul 27 '15 at 13:51
  • the `video=screen-capture-recorder` is the parameter the `dshow` device/format expects. if you're going to use `gdigrab` you will need to pass the corresponding format. Check the page I linked to for more. – Roberto Andrade Jul 27 '15 at 19:16