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

Commit 46176e5

Browse files
committed
Refactor V4L2 and X11 grabbers to share more code
1 parent 08655bb commit 46176e5

22 files changed

+749
-773
lines changed
File renamed without changes.

include/protoserver/ProtoConnection.h

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#pragma once
2+
3+
// stl includes
4+
#include <string>
5+
6+
// Qt includes
7+
#include <QColor>
8+
#include <QImage>
9+
#include <QTcpSocket>
10+
#include <QMap>
11+
12+
// hyperion util
13+
#include <utils/Image.h>
14+
#include <utils/ColorRgb.h>
15+
16+
// jsoncpp includes
17+
#include <message.pb.h>
18+
19+
///
20+
/// Connection class to setup an connection to the hyperion server and execute commands
21+
///
22+
class ProtoConnection
23+
{
24+
public:
25+
///
26+
/// Constructor
27+
///
28+
/// @param address The address of the Hyperion server (for example "192.168.0.32:19444)
29+
///
30+
ProtoConnection(const std::string & address);
31+
32+
///
33+
/// Destructor
34+
///
35+
~ProtoConnection();
36+
37+
/// Do not read reply messages from Hyperion if set to true
38+
void setSkipReply(bool skip);
39+
40+
///
41+
/// Set all leds to the specified color
42+
///
43+
/// @param color The color
44+
/// @param priority The priority
45+
/// @param duration The duration in milliseconds
46+
///
47+
void setColor(const ColorRgb & color, int priority, int duration = 1);
48+
49+
///
50+
/// Set the leds according to the given image (assume the image is stretched to the display size)
51+
///
52+
/// @param image The image
53+
/// @param priority The priority
54+
/// @param duration The duration in milliseconds
55+
///
56+
void setImage(const Image<ColorRgb> & image, int priority, int duration = -1);
57+
58+
///
59+
/// Clear the given priority channel
60+
///
61+
/// @param priority The priority
62+
///
63+
void clear(int priority);
64+
65+
///
66+
/// Clear all priority channels
67+
///
68+
void clearAll();
69+
70+
private:
71+
/// Try to connect to the Hyperion host
72+
void connectToHost();
73+
74+
///
75+
/// Send a command message and receive its reply
76+
///
77+
/// @param message The message to send
78+
///
79+
void sendMessage(const proto::HyperionRequest & message);
80+
81+
///
82+
/// Parse a reply message
83+
///
84+
/// @param reply The received reply
85+
///
86+
/// @return true if the reply indicates success
87+
///
88+
bool parseReply(const proto::HyperionReply & reply);
89+
90+
private:
91+
/// The TCP-Socket with the connection to the server
92+
QTcpSocket _socket;
93+
94+
/// Host address
95+
QString _host;
96+
97+
/// Host port
98+
uint16_t _port;
99+
100+
/// Skip receiving reply messages from Hyperion if set
101+
bool _skipReply;
102+
};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Qt includes
2+
#include <QObject>
3+
4+
// hyperion includes
5+
#include <utils/Image.h>
6+
#include <utils/ColorRgb.h>
7+
8+
// hyperion proto includes
9+
#include "protoserver/ProtoConnection.h"
10+
11+
/// This class handles callbacks from the V4L2 grabber
12+
class ProtoConnectionWrapper : public QObject
13+
{
14+
Q_OBJECT
15+
16+
public:
17+
ProtoConnectionWrapper(const std::string & address, int priority, int duration_ms, bool skipProtoReply);
18+
virtual ~ProtoConnectionWrapper();
19+
20+
public slots:
21+
/// Handle a single image
22+
/// @param image The image to process
23+
void receiveImage(const Image<ColorRgb> & image);
24+
25+
private:
26+
/// Priority for calls to Hyperion
27+
const int _priority;
28+
29+
/// Duration for color calls to Hyperion
30+
const int _duration_ms;
31+
32+
/// Hyperion proto connection object
33+
ProtoConnection _connection;
34+
};

libsrc/grabber/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
21
if (ENABLE_DISPMANX)
32
add_subdirectory(dispmanx)
43
endif (ENABLE_DISPMANX)
54

65
if (ENABLE_V4L2)
76
add_subdirectory(v4l2)
87
endif (ENABLE_V4L2)
8+
9+
if (ENABLE_X11)
10+
add_subdirectory(x11)
11+
endif()

libsrc/grabber/x11/CMakeLists.txt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Define the current source locations
2+
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber)
3+
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/x11)
4+
5+
# Find X11
6+
find_package(X11 REQUIRED)
7+
8+
include_directories(
9+
${QT_INCLUDES}
10+
${X11_INCLUDES}
11+
)
12+
13+
SET(X11_QT_HEADERS
14+
${CURRENT_HEADER_DIR}/X11Grabber.h
15+
)
16+
17+
SET(X11_HEADERS
18+
${CURRENT_HEADER_DIR}/X11Grabber.h
19+
)
20+
21+
SET(X11_SOURCES
22+
${CURRENT_SOURCE_DIR}/X11Grabber.cpp
23+
)
24+
25+
QT4_WRAP_CPP(X11_HEADERS_MOC ${X11_QT_HEADERS})
26+
27+
add_library(x11-grabber
28+
${X11_HEADERS}
29+
${X11_SOURCES}
30+
${X11_QT_HEADERS}
31+
${X11_HEADERS_MOC}
32+
)
33+
34+
target_link_libraries(x11-grabber
35+
hyperion
36+
${QT_LIBRARIES}
37+
)

libsrc/grabber/x11/X11Grabber.cpp

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// STL includes
2+
#include <iostream>
3+
#include <cstdint>
4+
5+
// X11 includes
6+
#include <X11/Xutil.h>
7+
8+
// X11Grabber includes
9+
#include <grabber/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()
46+
{
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);
113+
114+
return 0;
115+
}

libsrc/protoserver/CMakeLists.txt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ include_directories(
1010
# Group the headers that go through the MOC compiler
1111
set(ProtoServer_QT_HEADERS
1212
${CURRENT_HEADER_DIR}/ProtoServer.h
13+
${CURRENT_HEADER_DIR}/ProtoConnection.h
1314
${CURRENT_SOURCE_DIR}/ProtoClientConnection.h
15+
${CURRENT_HEADER_DIR}/ProtoConnectionWrapper.h
1416
)
1517

1618
set(ProtoServer_HEADERS
@@ -19,6 +21,8 @@ set(ProtoServer_HEADERS
1921
set(ProtoServer_SOURCES
2022
${CURRENT_SOURCE_DIR}/ProtoServer.cpp
2123
${CURRENT_SOURCE_DIR}/ProtoClientConnection.cpp
24+
${CURRENT_SOURCE_DIR}/ProtoConnection.cpp
25+
${CURRENT_SOURCE_DIR}/ProtoConnectionWrapper.cpp
2226
)
2327

2428
set(ProtoServer_PROTOS
@@ -44,5 +48,5 @@ add_library(protoserver
4448
target_link_libraries(protoserver
4549
hyperion
4650
hyperion-utils
47-
${PROTOBUF_LIBRARIES}
48-
${QT_LIBRARIES})
51+
${PROTOBUF_LIBRARIES}
52+
${QT_LIBRARIES})

0 commit comments

Comments
 (0)