XRender support for X11 Grabber (#649)

* Update X11Grabber.h

* Update X11Grabber.cpp

* Update CMakeLists.txt

* Update hyperion-x11.cpp

* Update X11Wrapper.cpp

* Update X11Wrapper.h


Former-commit-id: d2f7cb0e22248a0c2963bf53728f2e0d7bb9dee1
This commit is contained in:
Paulchen-Panther 2016-05-24 19:55:50 +02:00 committed by brindosch
parent 84a9125542
commit 409ef383f3
6 changed files with 105 additions and 25 deletions

View File

@ -6,7 +6,6 @@
// X11 includes
#include <X11/Xlib.h>
#include <X11/extensions/Xrender.h>
#include <X11/extensions/XShm.h>
#include <sys/ipc.h>
@ -16,7 +15,7 @@ class X11Grabber
{
public:
X11Grabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation);
X11Grabber(bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation);
virtual ~X11Grabber();
@ -28,7 +27,8 @@ public:
private:
ImageResampler _imageResampler;
bool _useXGetImage, _XShmAvailable, _XShmPixmapAvailable, _XRenderAvailable;
int _cropLeft;
int _cropRight;
int _cropTop;
@ -41,6 +41,13 @@ private:
Display* _x11Display;
Window _window;
XWindowAttributes _windowAttr;
Pixmap _pixmap;
XRenderPictFormat* _srcFormat;
XRenderPictFormat* _dstFormat;
XRenderPictureAttributes _pictAttr;
Picture _srcPicture;
Picture _dstPicture;
unsigned _screenWidth;
unsigned _screenHeight;

View File

@ -2,19 +2,22 @@
#include <iostream>
#include <cstdint>
// X11 includes
#include <X11/Xutil.h>
// X11Grabber includes
#include <grabber/X11Grabber.h>
X11Grabber::X11Grabber(int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation) :
X11Grabber::X11Grabber(bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation) :
_imageResampler(),
_useXGetImage(useXGetImage),
_cropLeft(cropLeft),
_cropRight(cropRight),
_cropTop(cropTop),
_cropBottom(cropBottom),
_x11Display(nullptr),
_pixmap(None),
_srcFormat(nullptr),
_dstFormat(nullptr),
_srcPicture(None),
_dstPicture(None),
_screenWidth(0),
_screenHeight(0),
_croppedWidth(0),
@ -23,7 +26,9 @@ X11Grabber::X11Grabber(int cropLeft, int cropRight, int cropTop, int cropBottom,
{
_imageResampler.setHorizontalPixelDecimation(horizontalPixelDecimation);
_imageResampler.setVerticalPixelDecimation(verticalPixelDecimation);
_imageResampler.setCropping(0, 0, 0, 0); // cropping is performed by XShmGetImage
_imageResampler.setCropping(0, 0, 0, 0); // cropping is performed by XShmGetImage or XGetImage
memset(&_pictAttr, 0, sizeof(_pictAttr));
_pictAttr.repeat = RepeatNone;
}
X11Grabber::~X11Grabber()
@ -38,23 +43,45 @@ X11Grabber::~X11Grabber()
void X11Grabber::freeResources()
{
// Cleanup allocated resources of the X11 grab
XShmDetach(_x11Display, &_shminfo);
XDestroyImage(_xImage);
shmdt(_shminfo.shmaddr);
shmctl(_shminfo.shmid, IPC_RMID, 0);
if(_XShmAvailable && !_useXGetImage) {
XShmDetach(_x11Display, &_shminfo);
shmdt(_shminfo.shmaddr);
shmctl(_shminfo.shmid, IPC_RMID, 0);
}
if (_XRenderAvailable && !_useXGetImage) {
XRenderFreePicture(_x11Display, _srcPicture);
XRenderFreePicture(_x11Display, _dstPicture);
XFreePixmap(_x11Display, _pixmap);
}
}
void X11Grabber::setupResources()
{
_xImage = XShmCreateImage(_x11Display, _windowAttr.visual,
_windowAttr.depth, ZPixmap, NULL, &_shminfo,
_croppedWidth, _croppedHeight);
if(_XShmAvailable && !_useXGetImage) {
_xImage = XShmCreateImage(_x11Display, _windowAttr.visual,
_windowAttr.depth, ZPixmap, NULL, &_shminfo,
_croppedWidth, _croppedHeight);
_shminfo.shmid = shmget(IPC_PRIVATE, _xImage->bytes_per_line * _xImage->height, IPC_CREAT|0777);
_xImage->data = (char*)shmat(_shminfo.shmid,0,0);
_shminfo.shmaddr = _xImage->data;
_shminfo.readOnly = False;
_shminfo.shmid = shmget(IPC_PRIVATE, _xImage->bytes_per_line * _xImage->height, IPC_CREAT|0777);
_shminfo.shmaddr = _xImage->data = (char*)shmat(_shminfo.shmid,0,0);
_shminfo.readOnly = False;
XShmAttach(_x11Display, &_shminfo);
XShmAttach(_x11Display, &_shminfo);
}
if (_XRenderAvailable && !_useXGetImage) {
if(_XShmPixmapAvailable) {
_pixmap = XShmCreatePixmap(_x11Display, _window, _xImage->data, &_shminfo, _croppedWidth, _croppedHeight, _windowAttr.depth);
} else {
_pixmap = XCreatePixmap(_x11Display, _window, _croppedWidth, _croppedHeight, _windowAttr.depth);
}
_srcFormat = XRenderFindVisualFormat(_x11Display, _windowAttr.visual);
_dstFormat = XRenderFindVisualFormat(_x11Display, _windowAttr.visual);
_srcPicture = XRenderCreatePicture(_x11Display, _window, _srcFormat, CPRepeat, &_pictAttr);
_dstPicture = XRenderCreatePicture(_x11Display, _pixmap, _dstFormat, CPRepeat, &_pictAttr);
XRenderSetPictureFilter(_x11Display, _srcPicture, "bilinear", NULL, 0);
}
}
bool X11Grabber::Setup()
@ -72,14 +99,48 @@ bool X11Grabber::Setup()
_window = DefaultRootWindow(_x11Display);
int dummy, pixmaps_supported;
_XRenderAvailable = XRenderQueryExtension(_x11Display, &dummy, &dummy);
_XShmAvailable = XShmQueryExtension(_x11Display);
XShmQueryVersion(_x11Display, &dummy, &dummy, &pixmaps_supported);
_XShmPixmapAvailable = pixmaps_supported && XShmPixmapFormat(_x11Display) == ZPixmap;
return true;
}
}
Image<ColorRgb> & X11Grabber::grab()
{
updateScreenDimensions();
if (_XRenderAvailable && !_useXGetImage) {
XRenderComposite( _x11Display, // *dpy,
PictOpSrc, // op,
_srcPicture, // src
None, // mask
_dstPicture, // dst
_cropLeft, // src_x
_cropTop, // src_y
0, // mask_x
0, // mask_y
0, // dst_x
0, // dst_y
_croppedWidth, // width
_croppedHeight); // height
XSync(_x11Display, False);
if (_XShmAvailable) {
XShmGetImage(_x11Display, _pixmap, _xImage, 0, 0, AllPlanes);
} else {
_xImage = XGetImage(_x11Display, _pixmap, 0, 0, _croppedWidth, _croppedHeight, AllPlanes, ZPixmap);
}
} else {
if (_XShmAvailable && !_useXGetImage) {
XShmGetImage(_x11Display, _window, _xImage, _cropLeft, _cropTop, AllPlanes);
} else {
_xImage = XGetImage(_x11Display, _window, _cropLeft, _cropTop, _croppedWidth, _croppedHeight, AllPlanes, ZPixmap);
}
}
XShmGetImage(_x11Display, _window, _xImage, _cropLeft, _cropTop, 0x00FFFFFF);
if (_xImage == nullptr)
{
std::cerr << "X11GRABBER ERROR: Grab failed" << std::endl;
@ -125,6 +186,14 @@ int X11Grabber::updateScreenDimensions()
_croppedHeight = _screenHeight - _cropTop - _cropBottom;
else
_croppedHeight = _screenHeight;
std::cout << "X11GRABBER INFO: Using ";
if (_XRenderAvailable && !_useXGetImage) {
std::cout << "XRender for grabbing" << std::endl;
} else {
std::cout << "XGetImage for grabbing" << std::endl;
}
setupResources();

View File

@ -52,6 +52,7 @@ target_link_libraries(${PROJECT_NAME}
protoserver
x11-grabber
${X11_LIBRARIES}
${X11_Xrender_LIB}
pthread
)

View File

@ -2,9 +2,9 @@
// Hyperion-X11 includes
#include "X11Wrapper.h"
X11Wrapper::X11Wrapper(int grabInterval, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation) :
X11Wrapper::X11Wrapper(int grabInterval, bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation) :
_timer(this),
_grabber(cropLeft, cropRight, cropTop, cropBottom, horizontalPixelDecimation, verticalPixelDecimation)
_grabber(useXGetImage, cropLeft, cropRight, cropTop, cropBottom, horizontalPixelDecimation, verticalPixelDecimation)
{
_timer.setSingleShot(false);
_timer.setInterval(grabInterval);

View File

@ -9,7 +9,7 @@ class X11Wrapper : public QObject
{
Q_OBJECT
public:
X11Wrapper(int grabInterval, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation);
X11Wrapper(int grabInterval, bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation);
const Image<ColorRgb> & getScreenshot();

View File

@ -36,6 +36,7 @@ int main(int argc, char ** argv)
ParameterSet & parameters = optionParser.getParameters();
IntParameter & argFps = parameters.add<IntParameter> ('f', "framerate", "Capture frame rate [default: 10]");
SwitchParameter<> & argXGetImage = parameters.add<SwitchParameter<>> ('x', "xgetimage", "Use XGetImage instead of XRender");
IntParameter & argCropWidth = parameters.add<IntParameter> (0x0, "crop-width", "Number of pixels to crop from the left and right sides of the picture before decimation [default: 0]");
IntParameter & argCropHeight = parameters.add<IntParameter> (0x0, "crop-height", "Number of pixels to crop from the top and the bottom of the picture before decimation [default: 0]");
IntParameter & argCropLeft = parameters.add<IntParameter> (0x0, "crop-left", "Number of pixels to crop from the left of the picture before decimation (overrides --crop-width)");
@ -75,8 +76,10 @@ int main(int argc, char ** argv)
// Create the X11 grabbing stuff
int grabInterval = 1000 / argFps.getValue();
bool useXGetImage = argXGetImage.isSet();
X11Wrapper x11Wrapper(
grabInterval,
useXGetImage,
argCropLeft.getValue(),
argCropRight.getValue(),
argCropTop.getValue(),