Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fastest method for screen capturing on Linux

This question is similar to this one

Fastest method of screen capturing

but for linux/X11.

To be more specific, i need a method to capture the pixel images of one window (the programmatic equivalent of alt-print screen in windows) running on a X11 diplay.

Notes and requirements:

1) Even if a new window is placed on top of the window that is being captured, the pixel image should still point to the original application window without any occlusion

2) it is not needed that the application window to be seen by the user, i just need to store the pixel buffers/images for video purposes

other alternatives that i've explored are:

1) xvfb - it works but it does does CPU rendering, which is slow and wasteful of a good GPU

2) x11 inside many lxc - theoretically could work but is complex to setup, and i'm not sure it will scale well with many windows being captured

suggestions and ideas are welcome

like image 691
lurscher Avatar asked Nov 20 '12 18:11

lurscher


People also ask

Does Linux have a screen recorder?

There is a built-in Linux screen recorder available in Ubuntu, integrated into the GNOME Shell desktop. It is a good option for simple screen captures that don't require audio. To access it, you can use the following keyboard shortcut: Ctrl + Alt + Shift + R.

How do I take a screenshot on Linux?

Use the shortcut keys PrintScreen to capture the whole desktop and Alt+PrintScreen to capture the current window (these also work under Windows). Or select Applications -> Accessories -> Screenshot from the menus.

How do you take a scrolling screenshot in Linux?

Alt + Prt Scrn to take a screenshot of a window. Shift + Prt Scrn to take a screenshot of an area you select.


3 Answers

This is possible using VirtualGL in a server with hardware acceleration. Basically just configure the server appropiately, then either on the same machine or on a machine in the same network, run

export DISPLAY=<your xvfb display>
vglrun <your_app>

This will have the following advantages:

1) your app will render using virtualGL, which will use the hardware

2) VirtualGL will display your 3D context inside the Xfvb display, which will only render the 2D widgets in CPU

3) configure Xvfb to render to a framebuffer

4) profit!

like image 72
diffeomorphism Avatar answered Oct 16 '22 14:10

diffeomorphism


This is not possible with pure X11.

You can get what you want with compositing, but only on servers which support it (most modern ones do). This actually has nothing to do with window managers. A WM is just another client, albeit with some special abilities, but those are unrelated to compositing. You can use the same compositing API.

man xcomposite should get you started.

like image 24
n. 1.8e9-where's-my-share m. Avatar answered Oct 16 '22 14:10

n. 1.8e9-where's-my-share m.


I've seen comments saying this can't be done in X11 so there may be something I don't understand but i am able to capture my screen using the following code.

#include <X11/Xlib.h> //-lX11
#include <X11/Xutil.h>
#include <X11/Xmd.h> 
#include <X11/Xatom.h>
#include <jpeglib.h> //-ljpeg 

void CopyDesktopImage(std::string sFilePath_Name)
{  
    Display *dis=XOpenDisplay((char *)0);
    Screen *scr = XDefaultScreenOfDisplay(dis);
    Drawable drawable = XDefaultRootWindow(dis);

    XImage *image = XGetImage(dis, drawable, 0, 0, scr->width, scr->height, AllPlanes, ZPixmap);
    Save_XImage_to_JPG(image, sFilePath_Name.c_str(), 75);
    XDestroyImage(image);

    XCloseDisplay(dis); 
}

void Save_XImage_to_JPG(XImage *image, std::string FileName, int Quality)
{
    FILE* outfile = fopen(FileName.c_str(), "wb");
    if(outfile == NULL) return;

    jpeg_compress_struct cinfo;
    jpeg_error_mgr       jerr;

    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_compress(&cinfo);
    jpeg_stdio_dest(&cinfo, outfile);

    cinfo.image_width      = image->width;
    cinfo.image_height     = image->height;
    cinfo.input_components = image->bitmap_unit >> 3;
    cinfo.in_color_space   = JCS_EXT_BGRX;

    jpeg_set_defaults(&cinfo);
    /*set the quality [0..100]  */
    jpeg_set_quality(&cinfo, Quality, true);
    jpeg_start_compress(&cinfo, true);

    JSAMPROW row_pointer;          /* pointer to a single row */

    while (cinfo.next_scanline < cinfo.image_height) 
    {
        row_pointer = (JSAMPROW) &image->data[cinfo.next_scanline*image->bytes_per_line];
        jpeg_write_scanlines(&cinfo, &row_pointer, 1);
    }
    jpeg_finish_compress(&cinfo);

    fclose(outfile);
}
like image 5
AtomClock Avatar answered Oct 16 '22 16:10

AtomClock