Skip to content
This repository was archived by the owner on May 6, 2021. It is now read-only.

Commit 17ad66f

Browse files
committed
Implemented the X11-grabber (based on v4l code).
1 parent 2915def commit 17ad66f

File tree

8 files changed

+365
-12
lines changed

8 files changed

+365
-12
lines changed

src/hyperion-x11/CMakeLists.txt

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,42 +10,55 @@ find_package(Protobuf REQUIRED)
1010
# find Qt4
1111
find_package(Qt4 REQUIRED QtCore QtGui QtNetwork)
1212

13+
# Find X11
14+
find_package(X11 REQUIRED)
15+
1316
include_directories(
1417
${CMAKE_CURRENT_BINARY_DIR}
1518
${PROTOBUF_INCLUDE_DIRS}
1619
${QT_INCLUDES}
20+
${X11_INCLUDES}
1721
)
1822

23+
set(Hyperion_X11_QT_HEADERS
24+
ProtoWrapper.h
25+
X11Wrapper.h)
26+
1927
set(Hyperion_X11_HEADERS
2028
X11Grabber.h
2129
../hyperion-v4l2/ProtoConnection.h
2230
)
2331

2432
set(Hyperion_X11_SOURCES
33+
hyperion-x11.cpp
34+
ProtoWrapper.cpp
2535
X11Grabber.cpp
36+
X11Wrapper.cpp
2637
../hyperion-v4l2/ProtoConnection.cpp
2738
)
2839

2940
set(Hyperion_X11_PROTOS
3041
${CMAKE_CURRENT_SOURCE_DIR}/../../libsrc/protoserver/message.proto
3142
)
3243

33-
protobuf_generate_cpp(Hyperion_X11_PROTO_SRCS Hyperion_X11_PROTO_HDRS
34-
${Hyperion_X11_PROTOS}
35-
)
44+
QT4_WRAP_CPP(Hyperion_X11_HEADERS_MOC ${Hyperion_X11_QT_HEADERS})
45+
46+
protobuf_generate_cpp(Hyperion_X11_PROTO_SRCS Hyperion_X11_PROTO_HDRS ${Hyperion_X11_PROTOS})
3647

3748
add_executable(hyperion-x11
3849
${Hyperion_X11_HEADERS}
3950
${Hyperion_X11_SOURCES}
4051
${Hyperion_X11_PROTO_SRCS}
4152
${Hyperion_X11_PROTO_HDRS}
53+
${Hyperion_X11_HEADERS_MOC}
4254
)
4355

4456
target_link_libraries(hyperion-x11
4557
getoptPlusPlus
4658
blackborder
4759
hyperion-utils
4860
${PROTOBUF_LIBRARIES}
61+
${X11_LIBRARIES}
4962
pthread
5063
)
5164

src/hyperion-x11/ProtoWrapper.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
//
3+
#include "ProtoWrapper.h"
4+
5+
ProtoWrapper::ProtoWrapper(const std::string & protoAddress, const bool skipReply) :
6+
_priority(200),
7+
_duration_ms(2000),
8+
_connection(protoAddress)
9+
{
10+
_connection.setSkipReply(skipReply);
11+
}
12+
13+
void ProtoWrapper::process(const Image<ColorRgb> & image)
14+
{
15+
std::cout << "Attempt to send screenshot" << std::endl;
16+
_connection.setImage(image, _priority, _duration_ms);
17+
}

src/hyperion-x11/ProtoWrapper.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
// QT includes
3+
#include <QObject>
4+
5+
6+
#include "../hyperion-v4l2/ProtoConnection.h"
7+
8+
class ProtoWrapper : public QObject
9+
{
10+
Q_OBJECT
11+
public:
12+
ProtoWrapper(const std::string & protoAddress, const bool skipReply);
13+
14+
public slots:
15+
void process(const Image<ColorRgb> & image);
16+
17+
private:
18+
19+
int _priority;
20+
int _duration_ms;
21+
22+
ProtoConnection _connection;
23+
};

src/hyperion-x11/X11Grabber.cpp

Lines changed: 110 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,115 @@
1+
// STL includes
2+
#include <iostream>
3+
#include <cstdint>
14

2-
#include <X11/Xlib.h>
5+
// X11 includes
6+
#include <X11/Xutil.h>
37

4-
int main(int argc, char ** argv)
8+
// X11Grabber includes
9+
#include "X11Grabber.h"
10+
11+
X11Grabber::X11Grabber(const unsigned cropHorizontal, const unsigned cropVertical, const unsigned pixelDecimation) :
12+
_pixelDecimation(pixelDecimation),
13+
_cropWidth(cropHorizontal),
14+
_cropHeight(cropVertical),
15+
_x11Display(nullptr),
16+
_screenWidth(0),
17+
_screenHeight(0),
18+
_image(0,0)
19+
{
20+
// empty
21+
}
22+
23+
X11Grabber::~X11Grabber()
24+
{
25+
if (_x11Display != nullptr)
26+
{
27+
XCloseDisplay(_x11Display);
28+
}
29+
}
30+
31+
int X11Grabber::open()
32+
{
33+
const char * display_name = nullptr;
34+
_x11Display = XOpenDisplay(display_name);
35+
36+
if (_x11Display == nullptr)
37+
{
38+
std::cerr << "Failed to open the default X11-display" << std::endl;
39+
return -1;
40+
}
41+
42+
return 0;
43+
}
44+
45+
Image<ColorRgb> & X11Grabber::grab()
546
{
6-
Display * dspl;
7-
Drawable drwbl;
8-
int x = 0;
9-
int y = 0;
10-
int width = 0;
11-
int height = 0;
47+
if (_x11Display == nullptr)
48+
{
49+
open();
50+
}
51+
52+
updateScreenDimensions();
53+
54+
const int croppedWidth = _screenWidth - 2*_cropWidth;
55+
const int croppedHeight = _screenHeight - 2*_cropHeight;
56+
57+
// Capture the current screen
58+
XImage * xImage = XGetImage(_x11Display, DefaultRootWindow(_x11Display), _cropWidth, _cropHeight, croppedWidth, croppedHeight, AllPlanes, ZPixmap);
59+
if (xImage == nullptr)
60+
{
61+
std::cerr << "Grab failed" << std::endl;
62+
return _image;
63+
}
64+
65+
// Copy the capture XImage to the local image (and apply required decimation)
66+
ColorRgb * outputPtr = _image.memptr();
67+
for (int iY=(_pixelDecimation/2); iY<croppedHeight; iY+=_pixelDecimation)
68+
{
69+
for (int iX=(_pixelDecimation/2); iX<croppedWidth; iX+=_pixelDecimation)
70+
{
71+
// Extract the pixel from the X11-image
72+
const uint32_t pixel = uint32_t(XGetPixel(xImage, iX, iY));
73+
74+
// Assign the color value
75+
outputPtr->red = uint8_t((pixel >> 16) & 0xff);
76+
outputPtr->green = uint8_t((pixel >> 8) & 0xff);
77+
outputPtr->blue = uint8_t((pixel >> 0) & 0xff);
78+
79+
// Move to the next output pixel
80+
++outputPtr;
81+
}
82+
}
83+
// Cleanup allocated resources of the X11 grab
84+
XDestroyImage(xImage);
85+
86+
return _image;
87+
}
88+
89+
int X11Grabber::updateScreenDimensions()
90+
{
91+
XWindowAttributes window_attributes_return;
92+
const Status status = XGetWindowAttributes(_x11Display, DefaultRootWindow(_x11Display), &window_attributes_return);
93+
if (status == 0)
94+
{
95+
std::cerr << "Failed to obtain window attributes" << std::endl;
96+
return -1;
97+
}
98+
99+
if (_screenWidth == unsigned(window_attributes_return.width) && _screenHeight == unsigned(window_attributes_return.height))
100+
{
101+
// No update required
102+
return 0;
103+
}
104+
std::cout << "Update of screen resolution: [" << _screenWidth << "x" << _screenHeight <<"] => ";
105+
_screenWidth = window_attributes_return.width;
106+
_screenHeight = window_attributes_return.height;
107+
std::cout << "[" << _screenWidth << "x" << _screenHeight <<"]" << std::endl;
108+
109+
// Update the size of the buffer used to transfer the screenshot
110+
int width = (_screenWidth - 2 * _cropWidth + _pixelDecimation/2) / _pixelDecimation;
111+
int height = (_screenHeight - 2 * _cropHeight + _pixelDecimation/2) / _pixelDecimation;
112+
_image.resize(width, height);
12113

13-
XImage * xImage = XGetImage(dspl, drwbl, x, y, width, height, AllPlanes, ZPixmap);
114+
return 0;
14115
}

src/hyperion-x11/X11Grabber.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
// Hyperion-utils includes
3+
#include <utils/Image.h>
4+
#include <utils/ColorRgb.h>
5+
6+
// X11 includes
7+
#include <X11/Xlib.h>
8+
9+
class X11Grabber
10+
{
11+
public:
12+
13+
X11Grabber(const unsigned cropHorizontal, const unsigned cropVertical, const unsigned pixelDecimation);
14+
15+
virtual ~X11Grabber();
16+
17+
int open();
18+
19+
Image<ColorRgb> & grab();
20+
21+
private:
22+
23+
const unsigned _pixelDecimation;
24+
25+
const unsigned _cropWidth;
26+
const unsigned _cropHeight;
27+
28+
/// Reference to the X11 display (nullptr if not opened)
29+
Display * _x11Display;
30+
31+
unsigned _screenWidth;
32+
unsigned _screenHeight;
33+
34+
Image<ColorRgb> _image;
35+
36+
int updateScreenDimensions();
37+
};

src/hyperion-x11/X11Wrapper.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
// Hyperion-X11 includes
3+
#include "X11Wrapper.h"
4+
5+
X11Wrapper::X11Wrapper(const unsigned cropHorizontal, const unsigned cropVertical, const unsigned pixelDecimation) :
6+
_timer(this),
7+
_grabber(cropHorizontal, cropVertical, pixelDecimation)
8+
{
9+
// Connect capturing to the timeout signal of the timer
10+
connect(&_timer, SIGNAL(timeout()), this, SLOT(capture()));
11+
}
12+
13+
const Image<ColorRgb> & X11Wrapper::getScreenshot()
14+
{
15+
const Image<ColorRgb> & screenshot = _grabber.grab();
16+
return screenshot;
17+
}
18+
19+
void X11Wrapper::start()
20+
{
21+
_timer.start(200);
22+
}
23+
24+
void X11Wrapper::stop()
25+
{
26+
_timer.stop();
27+
}
28+
29+
void X11Wrapper::capture()
30+
{
31+
const Image<ColorRgb> & screenshot = _grabber.grab();
32+
emit sig_screenshot(screenshot);
33+
}

src/hyperion-x11/X11Wrapper.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
2+
// QT includes
3+
#include <QTimer>
4+
5+
// Hyperion-X11 includes
6+
#include "X11Grabber.h"
7+
8+
class X11Wrapper : public QObject
9+
{
10+
Q_OBJECT
11+
public:
12+
X11Wrapper(const unsigned cropHorizontal, const unsigned cropVertical, const unsigned pixelDecimation);
13+
14+
const Image<ColorRgb> & getScreenshot();
15+
16+
///
17+
/// Starts the timed capturing of screenshots
18+
///
19+
void start();
20+
21+
void stop();
22+
23+
signals:
24+
void sig_screenshot(const Image<ColorRgb> & screenshot);
25+
26+
private slots:
27+
///
28+
/// Performs a single screenshot capture and publishes the capture screenshot on the screenshot
29+
/// signal.
30+
///
31+
void capture();
32+
33+
private:
34+
/// The QT timer to generate capture-publish events
35+
QTimer _timer;
36+
37+
/// The grabber for creating screenshots
38+
X11Grabber _grabber;
39+
};

0 commit comments

Comments
 (0)