diff --git a/include/grabber/X11Grabber.h b/include/grabber/X11Grabber.h index b35031cf..d8e4783c 100644 --- a/include/grabber/X11Grabber.h +++ b/include/grabber/X11Grabber.h @@ -6,7 +6,6 @@ // X11 includes #include - #include #include #include @@ -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; diff --git a/libsrc/grabber/x11/X11Grabber.cpp b/libsrc/grabber/x11/X11Grabber.cpp index 5b86d86c..1e3e0b4c 100644 --- a/libsrc/grabber/x11/X11Grabber.cpp +++ b/libsrc/grabber/x11/X11Grabber.cpp @@ -2,19 +2,22 @@ #include #include -// X11 includes -#include - // X11Grabber includes #include -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 & 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(); diff --git a/src/hyperion-x11/CMakeLists.txt b/src/hyperion-x11/CMakeLists.txt index 87a66e12..a3a17d7c 100644 --- a/src/hyperion-x11/CMakeLists.txt +++ b/src/hyperion-x11/CMakeLists.txt @@ -52,6 +52,7 @@ target_link_libraries(${PROJECT_NAME} protoserver x11-grabber ${X11_LIBRARIES} + ${X11_Xrender_LIB} pthread ) diff --git a/src/hyperion-x11/X11Wrapper.cpp b/src/hyperion-x11/X11Wrapper.cpp index a0489fdf..8aa8fb49 100644 --- a/src/hyperion-x11/X11Wrapper.cpp +++ b/src/hyperion-x11/X11Wrapper.cpp @@ -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); diff --git a/src/hyperion-x11/X11Wrapper.h b/src/hyperion-x11/X11Wrapper.h index 18fab407..26ccc796 100644 --- a/src/hyperion-x11/X11Wrapper.h +++ b/src/hyperion-x11/X11Wrapper.h @@ -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 & getScreenshot(); diff --git a/src/hyperion-x11/hyperion-x11.cpp b/src/hyperion-x11/hyperion-x11.cpp index 776b3326..b7be000d 100644 --- a/src/hyperion-x11/hyperion-x11.cpp +++ b/src/hyperion-x11/hyperion-x11.cpp @@ -36,6 +36,7 @@ int main(int argc, char ** argv) ParameterSet & parameters = optionParser.getParameters(); IntParameter & argFps = parameters.add ('f', "framerate", "Capture frame rate [default: 10]"); + SwitchParameter<> & argXGetImage = parameters.add> ('x', "xgetimage", "Use XGetImage instead of XRender"); IntParameter & argCropWidth = parameters.add (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 (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 (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(),