mirror of
				https://github.com/hyperion-project/hyperion.ng.git
				synced 2025-03-01 10:33:28 +00:00 
			
		
		
		
	Refactor V4L2 and X11 grabbers to share more code
Former-commit-id: 46176e53d1acf39f9bd0c0ecbb8e5fb5ab4d45be
This commit is contained in:
		
							
								
								
									
										102
									
								
								include/protoserver/ProtoConnection.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								include/protoserver/ProtoConnection.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
// stl includes
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
// Qt includes
 | 
			
		||||
#include <QColor>
 | 
			
		||||
#include <QImage>
 | 
			
		||||
#include <QTcpSocket>
 | 
			
		||||
#include <QMap>
 | 
			
		||||
 | 
			
		||||
// hyperion util
 | 
			
		||||
#include <utils/Image.h>
 | 
			
		||||
#include <utils/ColorRgb.h>
 | 
			
		||||
 | 
			
		||||
// jsoncpp includes
 | 
			
		||||
#include <message.pb.h>
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
/// Connection class to setup an connection to the hyperion server and execute commands
 | 
			
		||||
///
 | 
			
		||||
class ProtoConnection
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    ///
 | 
			
		||||
    /// Constructor
 | 
			
		||||
    ///
 | 
			
		||||
    /// @param address The address of the Hyperion server (for example "192.168.0.32:19444)
 | 
			
		||||
    ///
 | 
			
		||||
    ProtoConnection(const std::string & address);
 | 
			
		||||
 | 
			
		||||
    ///
 | 
			
		||||
    /// Destructor
 | 
			
		||||
    ///
 | 
			
		||||
    ~ProtoConnection();
 | 
			
		||||
 | 
			
		||||
    /// Do not read reply messages from Hyperion if set to true
 | 
			
		||||
    void setSkipReply(bool skip);
 | 
			
		||||
 | 
			
		||||
    ///
 | 
			
		||||
    /// Set all leds to the specified color
 | 
			
		||||
    ///
 | 
			
		||||
    /// @param color The color
 | 
			
		||||
    /// @param priority The priority
 | 
			
		||||
    /// @param duration The duration in milliseconds
 | 
			
		||||
    ///
 | 
			
		||||
    void setColor(const ColorRgb & color, int priority, int duration = 1);
 | 
			
		||||
 | 
			
		||||
    ///
 | 
			
		||||
    /// Set the leds according to the given image (assume the image is stretched to the display size)
 | 
			
		||||
    ///
 | 
			
		||||
    /// @param image The image
 | 
			
		||||
    /// @param priority The priority
 | 
			
		||||
    /// @param duration The duration in milliseconds
 | 
			
		||||
    ///
 | 
			
		||||
    void setImage(const Image<ColorRgb> & image, int priority, int duration = -1);
 | 
			
		||||
 | 
			
		||||
    ///
 | 
			
		||||
    /// Clear the given priority channel
 | 
			
		||||
    ///
 | 
			
		||||
    /// @param priority The priority
 | 
			
		||||
    ///
 | 
			
		||||
    void clear(int priority);
 | 
			
		||||
 | 
			
		||||
    ///
 | 
			
		||||
    /// Clear all priority channels
 | 
			
		||||
    ///
 | 
			
		||||
    void clearAll();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    /// Try to connect to the Hyperion host
 | 
			
		||||
    void connectToHost();
 | 
			
		||||
 | 
			
		||||
    ///
 | 
			
		||||
    /// Send a command message and receive its reply
 | 
			
		||||
    ///
 | 
			
		||||
    /// @param message The message to send
 | 
			
		||||
    ///
 | 
			
		||||
    void sendMessage(const proto::HyperionRequest & message);
 | 
			
		||||
 | 
			
		||||
    ///
 | 
			
		||||
    /// Parse a reply message
 | 
			
		||||
    ///
 | 
			
		||||
    /// @param reply The received reply
 | 
			
		||||
    ///
 | 
			
		||||
    /// @return true if the reply indicates success
 | 
			
		||||
    ///
 | 
			
		||||
    bool parseReply(const proto::HyperionReply & reply);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    /// The TCP-Socket with the connection to the server
 | 
			
		||||
    QTcpSocket _socket;
 | 
			
		||||
 | 
			
		||||
    /// Host address
 | 
			
		||||
    QString _host;
 | 
			
		||||
 | 
			
		||||
    /// Host port
 | 
			
		||||
    uint16_t _port;
 | 
			
		||||
 | 
			
		||||
    /// Skip receiving reply messages from Hyperion if set
 | 
			
		||||
    bool _skipReply;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										34
									
								
								include/protoserver/ProtoConnectionWrapper.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								include/protoserver/ProtoConnectionWrapper.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
// Qt includes
 | 
			
		||||
#include <QObject>
 | 
			
		||||
 | 
			
		||||
// hyperion includes
 | 
			
		||||
#include <utils/Image.h>
 | 
			
		||||
#include <utils/ColorRgb.h>
 | 
			
		||||
 | 
			
		||||
// hyperion proto includes
 | 
			
		||||
#include "protoserver/ProtoConnection.h"
 | 
			
		||||
 | 
			
		||||
/// This class handles callbacks from the V4L2 grabber
 | 
			
		||||
class ProtoConnectionWrapper : public QObject
 | 
			
		||||
{
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    ProtoConnectionWrapper(const std::string & address, int priority, int duration_ms, bool skipProtoReply);
 | 
			
		||||
    virtual ~ProtoConnectionWrapper();
 | 
			
		||||
 | 
			
		||||
public slots:
 | 
			
		||||
    /// Handle a single image
 | 
			
		||||
    /// @param image The image to process
 | 
			
		||||
    void receiveImage(const Image<ColorRgb> & image);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    /// Priority for calls to Hyperion
 | 
			
		||||
    const int _priority;
 | 
			
		||||
 | 
			
		||||
    /// Duration for color calls to Hyperion
 | 
			
		||||
    const int _duration_ms;
 | 
			
		||||
 | 
			
		||||
    /// Hyperion proto connection object
 | 
			
		||||
    ProtoConnection _connection;
 | 
			
		||||
};
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
 | 
			
		||||
if (ENABLE_DISPMANX)
 | 
			
		||||
	add_subdirectory(dispmanx)
 | 
			
		||||
endif (ENABLE_DISPMANX)
 | 
			
		||||
@@ -6,3 +5,7 @@ endif (ENABLE_DISPMANX)
 | 
			
		||||
if (ENABLE_V4L2)
 | 
			
		||||
	add_subdirectory(v4l2)
 | 
			
		||||
endif (ENABLE_V4L2)
 | 
			
		||||
 | 
			
		||||
if (ENABLE_X11)
 | 
			
		||||
	add_subdirectory(x11)
 | 
			
		||||
endif()
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										37
									
								
								libsrc/grabber/x11/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								libsrc/grabber/x11/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
# Define the current source locations
 | 
			
		||||
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber)
 | 
			
		||||
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/x11)
 | 
			
		||||
 | 
			
		||||
# Find X11
 | 
			
		||||
find_package(X11 REQUIRED)
 | 
			
		||||
 | 
			
		||||
include_directories(
 | 
			
		||||
	${QT_INCLUDES}
 | 
			
		||||
	${X11_INCLUDES}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
SET(X11_QT_HEADERS
 | 
			
		||||
		${CURRENT_HEADER_DIR}/X11Grabber.h
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
SET(X11_HEADERS
 | 
			
		||||
	${CURRENT_HEADER_DIR}/X11Grabber.h
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
SET(X11_SOURCES
 | 
			
		||||
		${CURRENT_SOURCE_DIR}/X11Grabber.cpp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
QT4_WRAP_CPP(X11_HEADERS_MOC ${X11_QT_HEADERS})
 | 
			
		||||
 | 
			
		||||
add_library(x11-grabber
 | 
			
		||||
		${X11_HEADERS}
 | 
			
		||||
		${X11_SOURCES}
 | 
			
		||||
		${X11_QT_HEADERS}
 | 
			
		||||
		${X11_HEADERS_MOC}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
target_link_libraries(x11-grabber
 | 
			
		||||
	hyperion
 | 
			
		||||
	${QT_LIBRARIES}
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										115
									
								
								libsrc/grabber/x11/X11Grabber.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								libsrc/grabber/x11/X11Grabber.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,115 @@
 | 
			
		||||
// STL includes
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
// X11 includes
 | 
			
		||||
#include <X11/Xutil.h>
 | 
			
		||||
 | 
			
		||||
// X11Grabber includes
 | 
			
		||||
#include <grabber/X11Grabber.h>
 | 
			
		||||
 | 
			
		||||
X11Grabber::X11Grabber(const unsigned cropHorizontal, const unsigned cropVertical, const unsigned pixelDecimation) :
 | 
			
		||||
    _pixelDecimation(pixelDecimation),
 | 
			
		||||
    _cropWidth(cropHorizontal),
 | 
			
		||||
    _cropHeight(cropVertical),
 | 
			
		||||
    _x11Display(nullptr),
 | 
			
		||||
    _screenWidth(0),
 | 
			
		||||
    _screenHeight(0),
 | 
			
		||||
    _image(0,0)
 | 
			
		||||
{
 | 
			
		||||
    // empty
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
X11Grabber::~X11Grabber()
 | 
			
		||||
{
 | 
			
		||||
    if (_x11Display != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        XCloseDisplay(_x11Display);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int X11Grabber::open()
 | 
			
		||||
{
 | 
			
		||||
    const char * display_name = nullptr;
 | 
			
		||||
    _x11Display = XOpenDisplay(display_name);
 | 
			
		||||
 | 
			
		||||
    if (_x11Display == nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        std::cerr << "Failed to open the default X11-display" << std::endl;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Image<ColorRgb> & X11Grabber::grab()
 | 
			
		||||
{
 | 
			
		||||
    if (_x11Display == nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        open();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    updateScreenDimensions();
 | 
			
		||||
 | 
			
		||||
    const int croppedWidth  = _screenWidth  - 2*_cropWidth;
 | 
			
		||||
    const int croppedHeight = _screenHeight - 2*_cropHeight;
 | 
			
		||||
 | 
			
		||||
    // Capture the current screen
 | 
			
		||||
    XImage * xImage = XGetImage(_x11Display, DefaultRootWindow(_x11Display), _cropWidth, _cropHeight, croppedWidth, croppedHeight, AllPlanes, ZPixmap);
 | 
			
		||||
    if (xImage == nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        std::cerr << "Grab failed" << std::endl;
 | 
			
		||||
        return _image;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Copy the capture XImage to the local image (and apply required decimation)
 | 
			
		||||
    ColorRgb * outputPtr = _image.memptr();
 | 
			
		||||
    for (int iY=(_pixelDecimation/2); iY<croppedHeight; iY+=_pixelDecimation)
 | 
			
		||||
    {
 | 
			
		||||
        for (int iX=(_pixelDecimation/2); iX<croppedWidth; iX+=_pixelDecimation)
 | 
			
		||||
        {
 | 
			
		||||
            // Extract the pixel from the X11-image
 | 
			
		||||
            const uint32_t pixel = uint32_t(XGetPixel(xImage, iX, iY));
 | 
			
		||||
 | 
			
		||||
            // Assign the color value
 | 
			
		||||
            outputPtr->red   = uint8_t((pixel >> 16) & 0xff);
 | 
			
		||||
            outputPtr->green = uint8_t((pixel >> 8)  & 0xff);
 | 
			
		||||
            outputPtr->blue  = uint8_t((pixel >> 0)  & 0xff);
 | 
			
		||||
 | 
			
		||||
            // Move to the next output pixel
 | 
			
		||||
            ++outputPtr;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // Cleanup allocated resources of the X11 grab
 | 
			
		||||
    XDestroyImage(xImage);
 | 
			
		||||
 | 
			
		||||
    return _image;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int X11Grabber::updateScreenDimensions()
 | 
			
		||||
{
 | 
			
		||||
    XWindowAttributes window_attributes_return;
 | 
			
		||||
    const Status status = XGetWindowAttributes(_x11Display, DefaultRootWindow(_x11Display), &window_attributes_return);
 | 
			
		||||
    if (status == 0)
 | 
			
		||||
    {
 | 
			
		||||
        std::cerr << "Failed to obtain window attributes" << std::endl;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (_screenWidth == unsigned(window_attributes_return.width) && _screenHeight == unsigned(window_attributes_return.height))
 | 
			
		||||
    {
 | 
			
		||||
        // No update required
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    std::cout << "Update of screen resolution: [" << _screenWidth << "x" << _screenHeight <<"] => ";
 | 
			
		||||
    _screenWidth  = window_attributes_return.width;
 | 
			
		||||
    _screenHeight = window_attributes_return.height;
 | 
			
		||||
    std::cout << "[" << _screenWidth << "x" << _screenHeight <<"]" << std::endl;
 | 
			
		||||
 | 
			
		||||
    // Update the size of the buffer used to transfer the screenshot
 | 
			
		||||
    int width  = (_screenWidth  - 2 * _cropWidth  + _pixelDecimation/2) / _pixelDecimation;
 | 
			
		||||
    int height = (_screenHeight - 2 * _cropHeight + _pixelDecimation/2) / _pixelDecimation;
 | 
			
		||||
    _image.resize(width, height);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -10,7 +10,9 @@ include_directories(
 | 
			
		||||
# Group the headers that go through the MOC compiler
 | 
			
		||||
set(ProtoServer_QT_HEADERS
 | 
			
		||||
		${CURRENT_HEADER_DIR}/ProtoServer.h
 | 
			
		||||
		${CURRENT_HEADER_DIR}/ProtoConnection.h
 | 
			
		||||
		${CURRENT_SOURCE_DIR}/ProtoClientConnection.h
 | 
			
		||||
		${CURRENT_HEADER_DIR}/ProtoConnectionWrapper.h
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(ProtoServer_HEADERS
 | 
			
		||||
@@ -19,6 +21,8 @@ set(ProtoServer_HEADERS
 | 
			
		||||
set(ProtoServer_SOURCES
 | 
			
		||||
		${CURRENT_SOURCE_DIR}/ProtoServer.cpp
 | 
			
		||||
		${CURRENT_SOURCE_DIR}/ProtoClientConnection.cpp
 | 
			
		||||
		${CURRENT_SOURCE_DIR}/ProtoConnection.cpp
 | 
			
		||||
		${CURRENT_SOURCE_DIR}/ProtoConnectionWrapper.cpp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(ProtoServer_PROTOS
 | 
			
		||||
@@ -44,5 +48,5 @@ add_library(protoserver
 | 
			
		||||
target_link_libraries(protoserver
 | 
			
		||||
		hyperion
 | 
			
		||||
		hyperion-utils
 | 
			
		||||
        ${PROTOBUF_LIBRARIES}
 | 
			
		||||
        ${QT_LIBRARIES})
 | 
			
		||||
		${PROTOBUF_LIBRARIES}
 | 
			
		||||
		${QT_LIBRARIES})
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										188
									
								
								libsrc/protoserver/ProtoConnection.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										188
									
								
								libsrc/protoserver/ProtoConnection.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,188 @@
 | 
			
		||||
// stl includes
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
 | 
			
		||||
// Qt includes
 | 
			
		||||
#include <QRgb>
 | 
			
		||||
 | 
			
		||||
// protoserver includes
 | 
			
		||||
#include "protoserver/ProtoConnection.h"
 | 
			
		||||
 | 
			
		||||
ProtoConnection::ProtoConnection(const std::string & a) :
 | 
			
		||||
    _socket(),
 | 
			
		||||
    _skipReply(false)
 | 
			
		||||
{
 | 
			
		||||
    QString address(a.c_str());
 | 
			
		||||
    QStringList parts = address.split(":");
 | 
			
		||||
    if (parts.size() != 2)
 | 
			
		||||
    {
 | 
			
		||||
        throw std::runtime_error(QString("Wrong address: unable to parse address (%1)").arg(address).toStdString());
 | 
			
		||||
    }
 | 
			
		||||
    _host = parts[0];
 | 
			
		||||
 | 
			
		||||
    bool ok;
 | 
			
		||||
    _port = parts[1].toUShort(&ok);
 | 
			
		||||
    if (!ok)
 | 
			
		||||
    {
 | 
			
		||||
        throw std::runtime_error(QString("Wrong address: Unable to parse the port number (%1)").arg(parts[1]).toStdString());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // try to connect to host
 | 
			
		||||
    std::cout << "Connecting to Hyperion: " << _host.toStdString() << ":" << _port << std::endl;
 | 
			
		||||
    connectToHost();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ProtoConnection::~ProtoConnection()
 | 
			
		||||
{
 | 
			
		||||
    _socket.close();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProtoConnection::setSkipReply(bool skip)
 | 
			
		||||
{
 | 
			
		||||
    _skipReply = skip;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProtoConnection::setColor(const ColorRgb & color, int priority, int duration)
 | 
			
		||||
{
 | 
			
		||||
    proto::HyperionRequest request;
 | 
			
		||||
    request.set_command(proto::HyperionRequest::COLOR);
 | 
			
		||||
    proto::ColorRequest * colorRequest = request.MutableExtension(proto::ColorRequest::colorRequest);
 | 
			
		||||
    colorRequest->set_rgbcolor((color.red << 16) | (color.green << 8) | color.blue);
 | 
			
		||||
    colorRequest->set_priority(priority);
 | 
			
		||||
    colorRequest->set_duration(duration);
 | 
			
		||||
 | 
			
		||||
    // send command message
 | 
			
		||||
    sendMessage(request);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProtoConnection::setImage(const Image<ColorRgb> &image, int priority, int duration)
 | 
			
		||||
{
 | 
			
		||||
    proto::HyperionRequest request;
 | 
			
		||||
    request.set_command(proto::HyperionRequest::IMAGE);
 | 
			
		||||
    proto::ImageRequest * imageRequest = request.MutableExtension(proto::ImageRequest::imageRequest);
 | 
			
		||||
    imageRequest->set_imagedata(image.memptr(), image.width() * image.height() * 3);
 | 
			
		||||
    imageRequest->set_imagewidth(image.width());
 | 
			
		||||
    imageRequest->set_imageheight(image.height());
 | 
			
		||||
    imageRequest->set_priority(priority);
 | 
			
		||||
    imageRequest->set_duration(duration);
 | 
			
		||||
 | 
			
		||||
    // send command message
 | 
			
		||||
    sendMessage(request);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProtoConnection::clear(int priority)
 | 
			
		||||
{
 | 
			
		||||
    proto::HyperionRequest request;
 | 
			
		||||
    request.set_command(proto::HyperionRequest::CLEAR);
 | 
			
		||||
    proto::ClearRequest * clearRequest = request.MutableExtension(proto::ClearRequest::clearRequest);
 | 
			
		||||
    clearRequest->set_priority(priority);
 | 
			
		||||
 | 
			
		||||
    // send command message
 | 
			
		||||
    sendMessage(request);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProtoConnection::clearAll()
 | 
			
		||||
{
 | 
			
		||||
    proto::HyperionRequest request;
 | 
			
		||||
    request.set_command(proto::HyperionRequest::CLEARALL);
 | 
			
		||||
 | 
			
		||||
    // send command message
 | 
			
		||||
    sendMessage(request);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProtoConnection::connectToHost()
 | 
			
		||||
{
 | 
			
		||||
    _socket.connectToHost(_host, _port);
 | 
			
		||||
    if (_socket.waitForConnected()) {
 | 
			
		||||
        std::cout << "Connected to Hyperion host" << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProtoConnection::sendMessage(const proto::HyperionRequest &message)
 | 
			
		||||
{
 | 
			
		||||
    if (_socket.state() == QAbstractSocket::UnconnectedState)
 | 
			
		||||
    {
 | 
			
		||||
        std::cout << "Currently disconnected: trying to connect to host" << std::endl;
 | 
			
		||||
        connectToHost();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (_socket.state() != QAbstractSocket::ConnectedState)
 | 
			
		||||
    {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // We only get here if we are connected
 | 
			
		||||
 | 
			
		||||
    // serialize message (FastWriter already appends a newline)
 | 
			
		||||
    std::string serializedMessage = message.SerializeAsString();
 | 
			
		||||
 | 
			
		||||
    int length = serializedMessage.size();
 | 
			
		||||
    const uint8_t header[] = {
 | 
			
		||||
        uint8_t((length >> 24) & 0xFF),
 | 
			
		||||
        uint8_t((length >> 16) & 0xFF),
 | 
			
		||||
        uint8_t((length >>  8) & 0xFF),
 | 
			
		||||
        uint8_t((length      ) & 0xFF)};
 | 
			
		||||
 | 
			
		||||
    // write message
 | 
			
		||||
    int count = 0;
 | 
			
		||||
    count += _socket.write(reinterpret_cast<const char *>(header), 4);
 | 
			
		||||
    count += _socket.write(reinterpret_cast<const char *>(serializedMessage.data()), length);
 | 
			
		||||
    if (!_socket.waitForBytesWritten())
 | 
			
		||||
    {
 | 
			
		||||
        std::cerr << "Error while writing data to host" << std::endl;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!_skipReply)
 | 
			
		||||
    {
 | 
			
		||||
        // read reply data
 | 
			
		||||
        QByteArray serializedReply;
 | 
			
		||||
        length = -1;
 | 
			
		||||
        while (length < 0 && serializedReply.size() < length+4)
 | 
			
		||||
        {
 | 
			
		||||
            // receive reply
 | 
			
		||||
            if (!_socket.waitForReadyRead())
 | 
			
		||||
            {
 | 
			
		||||
                std::cerr << "Error while reading data from host" << std::endl;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            serializedReply += _socket.readAll();
 | 
			
		||||
 | 
			
		||||
            if (length < 0 && serializedReply.size() >= 4)
 | 
			
		||||
            {
 | 
			
		||||
                // read the message size
 | 
			
		||||
                length =
 | 
			
		||||
                        ((serializedReply[0]<<24) & 0xFF000000) |
 | 
			
		||||
                        ((serializedReply[1]<<16) & 0x00FF0000) |
 | 
			
		||||
                        ((serializedReply[2]<< 8) & 0x0000FF00) |
 | 
			
		||||
                        ((serializedReply[3]    ) & 0x000000FF);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // parse reply data
 | 
			
		||||
        proto::HyperionReply reply;
 | 
			
		||||
        reply.ParseFromArray(serializedReply.constData()+4, length);
 | 
			
		||||
 | 
			
		||||
        // parse reply message
 | 
			
		||||
        parseReply(reply);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ProtoConnection::parseReply(const proto::HyperionReply &reply)
 | 
			
		||||
{
 | 
			
		||||
    bool success = false;
 | 
			
		||||
 | 
			
		||||
    if (!reply.success())
 | 
			
		||||
    {
 | 
			
		||||
        if (reply.has_error())
 | 
			
		||||
        {
 | 
			
		||||
            throw std::runtime_error("Error: " + reply.error());
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            throw std::runtime_error("Error: No error info");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return success;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								libsrc/protoserver/ProtoConnectionWrapper.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								libsrc/protoserver/ProtoConnectionWrapper.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
// protoserver includes
 | 
			
		||||
#include "protoserver/ProtoConnectionWrapper.h"
 | 
			
		||||
 | 
			
		||||
ProtoConnectionWrapper::ProtoConnectionWrapper(const std::string & address, int priority, int duration_ms, bool skipProtoReply) :
 | 
			
		||||
        _priority(priority),
 | 
			
		||||
        _duration_ms(duration_ms),
 | 
			
		||||
        _connection(address)
 | 
			
		||||
{
 | 
			
		||||
    _connection.setSkipReply(skipProtoReply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ProtoConnectionWrapper::~ProtoConnectionWrapper()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProtoConnectionWrapper::receiveImage(const Image<ColorRgb> & image)
 | 
			
		||||
{
 | 
			
		||||
    _connection.setImage(image, _priority, _duration_ms);
 | 
			
		||||
}
 | 
			
		||||
@@ -2,44 +2,29 @@ cmake_minimum_required(VERSION 2.8)
 | 
			
		||||
 | 
			
		||||
project(hyperion-v4l2)
 | 
			
		||||
 | 
			
		||||
# add protocol buffers
 | 
			
		||||
find_package(Protobuf REQUIRED)
 | 
			
		||||
 | 
			
		||||
# find Qt4
 | 
			
		||||
find_package(Qt4 REQUIRED QtCore QtGui QtNetwork)
 | 
			
		||||
 | 
			
		||||
include_directories(
 | 
			
		||||
	${CMAKE_CURRENT_BINARY_DIR}
 | 
			
		||||
	${CMAKE_CURRENT_BINARY_DIR}/../../libsrc/protoserver
 | 
			
		||||
	${PROTOBUF_INCLUDE_DIRS}
 | 
			
		||||
	${QT_INCLUDES}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(Hyperion_V4L2_QT_HEADERS
 | 
			
		||||
	ImageHandler.h
 | 
			
		||||
	ScreenshotHandler.h
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(Hyperion_V4L2_HEADERS
 | 
			
		||||
	VideoStandardParameter.h
 | 
			
		||||
	PixelFormatParameter.h
 | 
			
		||||
	ProtoConnection.h
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(Hyperion_V4L2_SOURCES
 | 
			
		||||
	hyperion-v4l2.cpp
 | 
			
		||||
	ProtoConnection.cpp
 | 
			
		||||
	ImageHandler.cpp
 | 
			
		||||
	ScreenshotHandler.cpp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(Hyperion_V4L2_PROTOS
 | 
			
		||||
	${CMAKE_CURRENT_SOURCE_DIR}/../../libsrc/protoserver/message.proto
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
protobuf_generate_cpp(Hyperion_V4L2_PROTO_SRCS Hyperion_V4L2_PROTO_HDRS
 | 
			
		||||
	${Hyperion_V4L2_PROTOS}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
QT4_WRAP_CPP(Hyperion_V4L2_MOC_SOURCES ${Hyperion_V4L2_QT_HEADERS})
 | 
			
		||||
 | 
			
		||||
add_executable(hyperion-v4l2
 | 
			
		||||
@@ -47,8 +32,6 @@ add_executable(hyperion-v4l2
 | 
			
		||||
	${Hyperion_V4L2_SOURCES}
 | 
			
		||||
	${Hyperion_V4L2_QT_HEADERS}
 | 
			
		||||
	${Hyperion_V4L2_MOC_SOURCES}
 | 
			
		||||
	${Hyperion_V4L2_PROTO_SRCS}
 | 
			
		||||
	${Hyperion_V4L2_PROTO_HDRS}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
target_link_libraries(hyperion-v4l2
 | 
			
		||||
@@ -56,7 +39,7 @@ target_link_libraries(hyperion-v4l2
 | 
			
		||||
	getoptPlusPlus
 | 
			
		||||
	blackborder
 | 
			
		||||
	hyperion-utils
 | 
			
		||||
	${PROTOBUF_LIBRARIES}
 | 
			
		||||
	protoserver
 | 
			
		||||
	pthread
 | 
			
		||||
	${QT_LIBRARIES}
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +0,0 @@
 | 
			
		||||
// hyperion-v4l2 includes
 | 
			
		||||
#include "ImageHandler.h"
 | 
			
		||||
 | 
			
		||||
ImageHandler::ImageHandler(const std::string & address, int priority, bool skipProtoReply) :
 | 
			
		||||
		_priority(priority),
 | 
			
		||||
		_connection(address)
 | 
			
		||||
{
 | 
			
		||||
	_connection.setSkipReply(skipProtoReply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ImageHandler::~ImageHandler()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ImageHandler::receiveImage(const Image<ColorRgb> & image)
 | 
			
		||||
{
 | 
			
		||||
	_connection.setImage(image, _priority, 1000);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
// Qt includes
 | 
			
		||||
#include <QObject>
 | 
			
		||||
 | 
			
		||||
// hyperion includes
 | 
			
		||||
#include <utils/Image.h>
 | 
			
		||||
#include <utils/ColorRgb.h>
 | 
			
		||||
 | 
			
		||||
// hyperion v4l2 includes
 | 
			
		||||
#include "ProtoConnection.h"
 | 
			
		||||
 | 
			
		||||
/// This class handles callbacks from the V4L2 grabber
 | 
			
		||||
class ImageHandler : public QObject
 | 
			
		||||
{
 | 
			
		||||
	Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	ImageHandler(const std::string & address, int priority, bool skipProtoReply);
 | 
			
		||||
	virtual ~ImageHandler();
 | 
			
		||||
 | 
			
		||||
public slots:
 | 
			
		||||
	/// Handle a single image
 | 
			
		||||
	/// @param image The image to process
 | 
			
		||||
	void receiveImage(const Image<ColorRgb> & image);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	/// Priority for calls to Hyperion
 | 
			
		||||
	const int _priority;
 | 
			
		||||
 | 
			
		||||
	/// Hyperion proto connection object
 | 
			
		||||
	ProtoConnection _connection;
 | 
			
		||||
};
 | 
			
		||||
@@ -1,188 +0,0 @@
 | 
			
		||||
// stl includes
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
 | 
			
		||||
// Qt includes
 | 
			
		||||
#include <QRgb>
 | 
			
		||||
 | 
			
		||||
// hyperion-v4l2 includes
 | 
			
		||||
#include "ProtoConnection.h"
 | 
			
		||||
 | 
			
		||||
ProtoConnection::ProtoConnection(const std::string & a) :
 | 
			
		||||
	_socket(),
 | 
			
		||||
	_skipReply(false)
 | 
			
		||||
{
 | 
			
		||||
	QString address(a.c_str());
 | 
			
		||||
	QStringList parts = address.split(":");
 | 
			
		||||
	if (parts.size() != 2)
 | 
			
		||||
	{
 | 
			
		||||
		throw std::runtime_error(QString("Wrong address: unable to parse address (%1)").arg(address).toStdString());
 | 
			
		||||
	}
 | 
			
		||||
	_host = parts[0];
 | 
			
		||||
 | 
			
		||||
	bool ok;
 | 
			
		||||
	_port = parts[1].toUShort(&ok);
 | 
			
		||||
	if (!ok)
 | 
			
		||||
	{
 | 
			
		||||
		throw std::runtime_error(QString("Wrong address: Unable to parse the port number (%1)").arg(parts[1]).toStdString());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// try to connect to host
 | 
			
		||||
	std::cout << "Connecting to Hyperion: " << _host.toStdString() << ":" << _port << std::endl;
 | 
			
		||||
	connectToHost();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ProtoConnection::~ProtoConnection()
 | 
			
		||||
{
 | 
			
		||||
	_socket.close();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProtoConnection::setSkipReply(bool skip)
 | 
			
		||||
{
 | 
			
		||||
	_skipReply = skip;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProtoConnection::setColor(const ColorRgb & color, int priority, int duration)
 | 
			
		||||
{
 | 
			
		||||
	proto::HyperionRequest request;
 | 
			
		||||
	request.set_command(proto::HyperionRequest::COLOR);
 | 
			
		||||
	proto::ColorRequest * colorRequest = request.MutableExtension(proto::ColorRequest::colorRequest);
 | 
			
		||||
	colorRequest->set_rgbcolor((color.red << 16) | (color.green << 8) | color.blue);
 | 
			
		||||
	colorRequest->set_priority(priority);
 | 
			
		||||
	colorRequest->set_duration(duration);
 | 
			
		||||
 | 
			
		||||
	// send command message
 | 
			
		||||
	sendMessage(request);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProtoConnection::setImage(const Image<ColorRgb> &image, int priority, int duration)
 | 
			
		||||
{
 | 
			
		||||
	proto::HyperionRequest request;
 | 
			
		||||
	request.set_command(proto::HyperionRequest::IMAGE);
 | 
			
		||||
	proto::ImageRequest * imageRequest = request.MutableExtension(proto::ImageRequest::imageRequest);
 | 
			
		||||
	imageRequest->set_imagedata(image.memptr(), image.width() * image.height() * 3);
 | 
			
		||||
	imageRequest->set_imagewidth(image.width());
 | 
			
		||||
	imageRequest->set_imageheight(image.height());
 | 
			
		||||
	imageRequest->set_priority(priority);
 | 
			
		||||
	imageRequest->set_duration(duration);
 | 
			
		||||
 | 
			
		||||
	// send command message
 | 
			
		||||
	sendMessage(request);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProtoConnection::clear(int priority)
 | 
			
		||||
{
 | 
			
		||||
	proto::HyperionRequest request;
 | 
			
		||||
	request.set_command(proto::HyperionRequest::CLEAR);
 | 
			
		||||
	proto::ClearRequest * clearRequest = request.MutableExtension(proto::ClearRequest::clearRequest);
 | 
			
		||||
	clearRequest->set_priority(priority);
 | 
			
		||||
 | 
			
		||||
	// send command message
 | 
			
		||||
	sendMessage(request);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProtoConnection::clearAll()
 | 
			
		||||
{
 | 
			
		||||
	proto::HyperionRequest request;
 | 
			
		||||
	request.set_command(proto::HyperionRequest::CLEARALL);
 | 
			
		||||
 | 
			
		||||
	// send command message
 | 
			
		||||
	sendMessage(request);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProtoConnection::connectToHost()
 | 
			
		||||
{
 | 
			
		||||
	_socket.connectToHost(_host, _port);
 | 
			
		||||
	if (_socket.waitForConnected()) {
 | 
			
		||||
		std::cout << "Connected to Hyperion host" << std::endl;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProtoConnection::sendMessage(const proto::HyperionRequest &message)
 | 
			
		||||
{
 | 
			
		||||
	if (_socket.state() == QAbstractSocket::UnconnectedState)
 | 
			
		||||
	{
 | 
			
		||||
		std::cout << "Currently disconnected: trying to connect to host" << std::endl;
 | 
			
		||||
		connectToHost();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (_socket.state() != QAbstractSocket::ConnectedState)
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// We only get here if we are connected
 | 
			
		||||
 | 
			
		||||
	// serialize message (FastWriter already appends a newline)
 | 
			
		||||
	std::string serializedMessage = message.SerializeAsString();
 | 
			
		||||
 | 
			
		||||
	int length = serializedMessage.size();
 | 
			
		||||
	const uint8_t header[] = {
 | 
			
		||||
		uint8_t((length >> 24) & 0xFF),
 | 
			
		||||
		uint8_t((length >> 16) & 0xFF),
 | 
			
		||||
		uint8_t((length >>  8) & 0xFF),
 | 
			
		||||
		uint8_t((length      ) & 0xFF)};
 | 
			
		||||
 | 
			
		||||
	// write message
 | 
			
		||||
	int count = 0;
 | 
			
		||||
	count += _socket.write(reinterpret_cast<const char *>(header), 4);
 | 
			
		||||
	count += _socket.write(reinterpret_cast<const char *>(serializedMessage.data()), length);
 | 
			
		||||
	if (!_socket.waitForBytesWritten())
 | 
			
		||||
	{
 | 
			
		||||
		std::cerr << "Error while writing data to host" << std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!_skipReply)
 | 
			
		||||
	{
 | 
			
		||||
		// read reply data
 | 
			
		||||
		QByteArray serializedReply;
 | 
			
		||||
		length = -1;
 | 
			
		||||
		while (length < 0 && serializedReply.size() < length+4)
 | 
			
		||||
		{
 | 
			
		||||
			// receive reply
 | 
			
		||||
			if (!_socket.waitForReadyRead())
 | 
			
		||||
			{
 | 
			
		||||
				std::cerr << "Error while reading data from host" << std::endl;
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			serializedReply += _socket.readAll();
 | 
			
		||||
 | 
			
		||||
			if (length < 0 && serializedReply.size() >= 4)
 | 
			
		||||
			{
 | 
			
		||||
				// read the message size
 | 
			
		||||
				length =
 | 
			
		||||
						((serializedReply[0]<<24) & 0xFF000000) |
 | 
			
		||||
						((serializedReply[1]<<16) & 0x00FF0000) |
 | 
			
		||||
						((serializedReply[2]<< 8) & 0x0000FF00) |
 | 
			
		||||
						((serializedReply[3]    ) & 0x000000FF);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// parse reply data
 | 
			
		||||
		proto::HyperionReply reply;
 | 
			
		||||
		reply.ParseFromArray(serializedReply.constData()+4, length);
 | 
			
		||||
 | 
			
		||||
		// parse reply message
 | 
			
		||||
		parseReply(reply);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ProtoConnection::parseReply(const proto::HyperionReply &reply)
 | 
			
		||||
{
 | 
			
		||||
	bool success = false;
 | 
			
		||||
 | 
			
		||||
	if (!reply.success())
 | 
			
		||||
	{
 | 
			
		||||
		if (reply.has_error())
 | 
			
		||||
		{
 | 
			
		||||
			throw std::runtime_error("Error: " + reply.error());
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			throw std::runtime_error("Error: No error info");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return success;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,102 +0,0 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
// stl includes
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
// Qt includes
 | 
			
		||||
#include <QColor>
 | 
			
		||||
#include <QImage>
 | 
			
		||||
#include <QTcpSocket>
 | 
			
		||||
#include <QMap>
 | 
			
		||||
 | 
			
		||||
// hyperion util
 | 
			
		||||
#include <utils/Image.h>
 | 
			
		||||
#include <utils/ColorRgb.h>
 | 
			
		||||
 | 
			
		||||
// jsoncpp includes
 | 
			
		||||
#include <message.pb.h>
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
/// Connection class to setup an connection to the hyperion server and execute commands
 | 
			
		||||
///
 | 
			
		||||
class ProtoConnection
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	///
 | 
			
		||||
	/// Constructor
 | 
			
		||||
	///
 | 
			
		||||
	/// @param address The address of the Hyperion server (for example "192.168.0.32:19444)
 | 
			
		||||
	///
 | 
			
		||||
	ProtoConnection(const std::string & address);
 | 
			
		||||
 | 
			
		||||
	///
 | 
			
		||||
	/// Destructor
 | 
			
		||||
	///
 | 
			
		||||
	~ProtoConnection();
 | 
			
		||||
 | 
			
		||||
	/// Do not read reply messages from Hyperion if set to true
 | 
			
		||||
	void setSkipReply(bool skip);
 | 
			
		||||
 | 
			
		||||
	///
 | 
			
		||||
	/// Set all leds to the specified color
 | 
			
		||||
	///
 | 
			
		||||
	/// @param color The color
 | 
			
		||||
	/// @param priority The priority
 | 
			
		||||
	/// @param duration The duration in milliseconds
 | 
			
		||||
	///
 | 
			
		||||
	void setColor(const ColorRgb & color, int priority, int duration = 1);
 | 
			
		||||
 | 
			
		||||
	///
 | 
			
		||||
	/// Set the leds according to the given image (assume the image is stretched to the display size)
 | 
			
		||||
	///
 | 
			
		||||
	/// @param image The image
 | 
			
		||||
	/// @param priority The priority
 | 
			
		||||
	/// @param duration The duration in milliseconds
 | 
			
		||||
	///
 | 
			
		||||
	void setImage(const Image<ColorRgb> & image, int priority, int duration = -1);
 | 
			
		||||
 | 
			
		||||
	///
 | 
			
		||||
	/// Clear the given priority channel
 | 
			
		||||
	///
 | 
			
		||||
	/// @param priority The priority
 | 
			
		||||
	///
 | 
			
		||||
	void clear(int priority);
 | 
			
		||||
 | 
			
		||||
	///
 | 
			
		||||
	/// Clear all priority channels
 | 
			
		||||
	///
 | 
			
		||||
	void clearAll();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	/// Try to connect to the Hyperion host
 | 
			
		||||
	void connectToHost();
 | 
			
		||||
 | 
			
		||||
	///
 | 
			
		||||
	/// Send a command message and receive its reply
 | 
			
		||||
	///
 | 
			
		||||
	/// @param message The message to send
 | 
			
		||||
	///
 | 
			
		||||
	void sendMessage(const proto::HyperionRequest & message);
 | 
			
		||||
 | 
			
		||||
	///
 | 
			
		||||
	/// Parse a reply message
 | 
			
		||||
	///
 | 
			
		||||
	/// @param reply The received reply
 | 
			
		||||
	///
 | 
			
		||||
	/// @return true if the reply indicates success
 | 
			
		||||
	///
 | 
			
		||||
	bool parseReply(const proto::HyperionReply & reply);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	/// The TCP-Socket with the connection to the server
 | 
			
		||||
	QTcpSocket _socket;
 | 
			
		||||
 | 
			
		||||
	/// Host address
 | 
			
		||||
	QString _host;
 | 
			
		||||
 | 
			
		||||
	/// Host port
 | 
			
		||||
	uint16_t _port;
 | 
			
		||||
 | 
			
		||||
	/// Skip receiving reply messages from Hyperion if set
 | 
			
		||||
	bool _skipReply;
 | 
			
		||||
};
 | 
			
		||||
@@ -15,11 +15,13 @@
 | 
			
		||||
// grabber includes
 | 
			
		||||
#include "grabber/V4L2Grabber.h"
 | 
			
		||||
 | 
			
		||||
// proto includes
 | 
			
		||||
#include "protoserver/ProtoConnection.h"
 | 
			
		||||
#include "protoserver/ProtoConnectionWrapper.h"
 | 
			
		||||
 | 
			
		||||
// hyperion-v4l2 includes
 | 
			
		||||
#include "ProtoConnection.h"
 | 
			
		||||
#include "VideoStandardParameter.h"
 | 
			
		||||
#include "PixelFormatParameter.h"
 | 
			
		||||
#include "ImageHandler.h"
 | 
			
		||||
#include "ScreenshotHandler.h"
 | 
			
		||||
 | 
			
		||||
using namespace vlofgren;
 | 
			
		||||
@@ -27,144 +29,144 @@ using namespace vlofgren;
 | 
			
		||||
// save the image as screenshot
 | 
			
		||||
void saveScreenshot(void *, const Image<ColorRgb> & image)
 | 
			
		||||
{
 | 
			
		||||
	// store as PNG
 | 
			
		||||
	QImage pngImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888);
 | 
			
		||||
	pngImage.save("screenshot.png");
 | 
			
		||||
    // store as PNG
 | 
			
		||||
    QImage pngImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888);
 | 
			
		||||
    pngImage.save("screenshot.png");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char** argv)
 | 
			
		||||
{
 | 
			
		||||
	QCoreApplication app(argc, argv);
 | 
			
		||||
    QCoreApplication app(argc, argv);
 | 
			
		||||
 | 
			
		||||
	// force the locale
 | 
			
		||||
	setlocale(LC_ALL, "C");
 | 
			
		||||
	QLocale::setDefault(QLocale::c());
 | 
			
		||||
    // force the locale
 | 
			
		||||
    setlocale(LC_ALL, "C");
 | 
			
		||||
    QLocale::setDefault(QLocale::c());
 | 
			
		||||
 | 
			
		||||
	// register the image type to use in signals
 | 
			
		||||
	qRegisterMetaType<Image<ColorRgb>>("Image<ColorRgb>");
 | 
			
		||||
    // register the image type to use in signals
 | 
			
		||||
    qRegisterMetaType<Image<ColorRgb>>("Image<ColorRgb>");
 | 
			
		||||
 | 
			
		||||
	try
 | 
			
		||||
	{
 | 
			
		||||
		// create the option parser and initialize all parameters
 | 
			
		||||
		OptionsParser optionParser("V4L capture application for Hyperion");
 | 
			
		||||
		ParameterSet & parameters = optionParser.getParameters();
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
        // create the option parser and initialize all parameters
 | 
			
		||||
        OptionsParser optionParser("V4L capture application for Hyperion");
 | 
			
		||||
        ParameterSet & parameters = optionParser.getParameters();
 | 
			
		||||
 | 
			
		||||
		StringParameter        & argDevice          = parameters.add<StringParameter>       ('d', "device",           "The device to use [default=/dev/video0]");
 | 
			
		||||
		VideoStandardParameter & argVideoStandard   = parameters.add<VideoStandardParameter>('v', "video-standard",   "The used video standard. Valid values are PAL or NTSC (optional)");
 | 
			
		||||
		PixelFormatParameter   & argPixelFormat     = parameters.add<PixelFormatParameter>  (0x0, "pixel-format",     "The use pixel format. Valid values are YUYV, UYVY, and RGB32 (optional)");
 | 
			
		||||
		IntParameter           & argInput           = parameters.add<IntParameter>          (0x0, "input",            "Input channel (optional)");
 | 
			
		||||
		IntParameter           & argWidth           = parameters.add<IntParameter>          (0x0, "width",            "Try to set the width of the video input (optional)");
 | 
			
		||||
		IntParameter           & argHeight          = parameters.add<IntParameter>          (0x0, "height",           "Try to set the height of the video input (optional)");
 | 
			
		||||
		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)");
 | 
			
		||||
		IntParameter           & argCropRight       = parameters.add<IntParameter>          (0x0, "crop-right",       "Number of pixels to crop from the right of the picture before decimation (overrides --crop-width)");
 | 
			
		||||
		IntParameter           & argCropTop         = parameters.add<IntParameter>          (0x0, "crop-top",         "Number of pixels to crop from the top of the picture before decimation (overrides --crop-height)");
 | 
			
		||||
		IntParameter           & argCropBottom      = parameters.add<IntParameter>          (0x0, "crop-bottom",      "Number of pixels to crop from the bottom of the picture before decimation (overrides --crop-height)");
 | 
			
		||||
		IntParameter           & argSizeDecimation  = parameters.add<IntParameter>          ('s', "size-decimator",   "Decimation factor for the output size [default=1]");
 | 
			
		||||
		IntParameter           & argFrameDecimation = parameters.add<IntParameter>          ('f', "frame-decimator",  "Decimation factor for the video frames [default=1]");
 | 
			
		||||
		SwitchParameter<>      & argScreenshot      = parameters.add<SwitchParameter<>>     (0x0, "screenshot",       "Take a single screenshot, save it to file and quit");
 | 
			
		||||
		DoubleParameter        & argSignalThreshold = parameters.add<DoubleParameter>       ('t', "signal-threshold", "The signal threshold for detecting the presence of a signal. Value should be between 0.0 and 1.0.");
 | 
			
		||||
		DoubleParameter        & argRedSignalThreshold = parameters.add<DoubleParameter>    (0x0, "red-threshold",    "The red signal threshold. Value should be between 0.0 and 1.0. (overrides --signal-threshold)");
 | 
			
		||||
		DoubleParameter        & argGreenSignalThreshold = parameters.add<DoubleParameter>  (0x0, "green-threshold",  "The green signal threshold. Value should be between 0.0 and 1.0. (overrides --signal-threshold)");
 | 
			
		||||
		DoubleParameter        & argBlueSignalThreshold = parameters.add<DoubleParameter>   (0x0, "blue-threshold",   "The blue signal threshold. Value should be between 0.0 and 1.0. (overrides --signal-threshold)");
 | 
			
		||||
		SwitchParameter<>      & arg3DSBS           = parameters.add<SwitchParameter<>>     (0x0, "3DSBS",            "Interpret the incoming video stream as 3D side-by-side");
 | 
			
		||||
		SwitchParameter<>      & arg3DTAB           = parameters.add<SwitchParameter<>>     (0x0, "3DTAB",            "Interpret the incoming video stream as 3D top-and-bottom");
 | 
			
		||||
		StringParameter        & argAddress         = parameters.add<StringParameter>       ('a', "address",          "Set the address of the hyperion server [default: 127.0.0.1:19445]");
 | 
			
		||||
		IntParameter           & argPriority        = parameters.add<IntParameter>          ('p', "priority",         "Use the provided priority channel (the lower the number, the higher the priority) [default: 800]");
 | 
			
		||||
		SwitchParameter<>      & argSkipReply       = parameters.add<SwitchParameter<>>     (0x0, "skip-reply",       "Do not receive and check reply messages from Hyperion");
 | 
			
		||||
		SwitchParameter<>      & argHelp            = parameters.add<SwitchParameter<>>     ('h', "help",             "Show this help message and exit");
 | 
			
		||||
        StringParameter        & argDevice          = parameters.add<StringParameter>       ('d', "device",           "The device to use [default=/dev/video0]");
 | 
			
		||||
        VideoStandardParameter & argVideoStandard   = parameters.add<VideoStandardParameter>('v', "video-standard",   "The used video standard. Valid values are PAL or NTSC (optional)");
 | 
			
		||||
        PixelFormatParameter   & argPixelFormat     = parameters.add<PixelFormatParameter>  (0x0, "pixel-format",     "The use pixel format. Valid values are YUYV, UYVY, and RGB32 (optional)");
 | 
			
		||||
        IntParameter           & argInput           = parameters.add<IntParameter>          (0x0, "input",            "Input channel (optional)");
 | 
			
		||||
        IntParameter           & argWidth           = parameters.add<IntParameter>          (0x0, "width",            "Try to set the width of the video input (optional)");
 | 
			
		||||
        IntParameter           & argHeight          = parameters.add<IntParameter>          (0x0, "height",           "Try to set the height of the video input (optional)");
 | 
			
		||||
        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)");
 | 
			
		||||
        IntParameter           & argCropRight       = parameters.add<IntParameter>          (0x0, "crop-right",       "Number of pixels to crop from the right of the picture before decimation (overrides --crop-width)");
 | 
			
		||||
        IntParameter           & argCropTop         = parameters.add<IntParameter>          (0x0, "crop-top",         "Number of pixels to crop from the top of the picture before decimation (overrides --crop-height)");
 | 
			
		||||
        IntParameter           & argCropBottom      = parameters.add<IntParameter>          (0x0, "crop-bottom",      "Number of pixels to crop from the bottom of the picture before decimation (overrides --crop-height)");
 | 
			
		||||
        IntParameter           & argSizeDecimation  = parameters.add<IntParameter>          ('s', "size-decimator",   "Decimation factor for the output size [default=1]");
 | 
			
		||||
        IntParameter           & argFrameDecimation = parameters.add<IntParameter>          ('f', "frame-decimator",  "Decimation factor for the video frames [default=1]");
 | 
			
		||||
        SwitchParameter<>      & argScreenshot      = parameters.add<SwitchParameter<>>     (0x0, "screenshot",       "Take a single screenshot, save it to file and quit");
 | 
			
		||||
        DoubleParameter        & argSignalThreshold = parameters.add<DoubleParameter>       ('t', "signal-threshold", "The signal threshold for detecting the presence of a signal. Value should be between 0.0 and 1.0.");
 | 
			
		||||
        DoubleParameter        & argRedSignalThreshold = parameters.add<DoubleParameter>    (0x0, "red-threshold",    "The red signal threshold. Value should be between 0.0 and 1.0. (overrides --signal-threshold)");
 | 
			
		||||
        DoubleParameter        & argGreenSignalThreshold = parameters.add<DoubleParameter>  (0x0, "green-threshold",  "The green signal threshold. Value should be between 0.0 and 1.0. (overrides --signal-threshold)");
 | 
			
		||||
        DoubleParameter        & argBlueSignalThreshold = parameters.add<DoubleParameter>   (0x0, "blue-threshold",   "The blue signal threshold. Value should be between 0.0 and 1.0. (overrides --signal-threshold)");
 | 
			
		||||
        SwitchParameter<>      & arg3DSBS           = parameters.add<SwitchParameter<>>     (0x0, "3DSBS",            "Interpret the incoming video stream as 3D side-by-side");
 | 
			
		||||
        SwitchParameter<>      & arg3DTAB           = parameters.add<SwitchParameter<>>     (0x0, "3DTAB",            "Interpret the incoming video stream as 3D top-and-bottom");
 | 
			
		||||
        StringParameter        & argAddress         = parameters.add<StringParameter>       ('a', "address",          "Set the address of the hyperion server [default: 127.0.0.1:19445]");
 | 
			
		||||
        IntParameter           & argPriority        = parameters.add<IntParameter>          ('p', "priority",         "Use the provided priority channel (the lower the number, the higher the priority) [default: 800]");
 | 
			
		||||
        SwitchParameter<>      & argSkipReply       = parameters.add<SwitchParameter<>>     (0x0, "skip-reply",       "Do not receive and check reply messages from Hyperion");
 | 
			
		||||
        SwitchParameter<>      & argHelp            = parameters.add<SwitchParameter<>>     ('h', "help",             "Show this help message and exit");
 | 
			
		||||
 | 
			
		||||
		// set defaults
 | 
			
		||||
		argDevice.setDefault("/dev/video0");
 | 
			
		||||
		argVideoStandard.setDefault(VIDEOSTANDARD_NO_CHANGE);
 | 
			
		||||
		argPixelFormat.setDefault(PIXELFORMAT_NO_CHANGE);
 | 
			
		||||
		argInput.setDefault(-1);
 | 
			
		||||
		argWidth.setDefault(-1);
 | 
			
		||||
		argHeight.setDefault(-1);
 | 
			
		||||
		argCropWidth.setDefault(0);
 | 
			
		||||
		argCropHeight.setDefault(0);
 | 
			
		||||
		argSizeDecimation.setDefault(1);
 | 
			
		||||
		argFrameDecimation.setDefault(1);
 | 
			
		||||
		argAddress.setDefault("127.0.0.1:19445");
 | 
			
		||||
		argPriority.setDefault(800);
 | 
			
		||||
		argSignalThreshold.setDefault(-1);
 | 
			
		||||
        // set defaults
 | 
			
		||||
        argDevice.setDefault("/dev/video0");
 | 
			
		||||
        argVideoStandard.setDefault(VIDEOSTANDARD_NO_CHANGE);
 | 
			
		||||
        argPixelFormat.setDefault(PIXELFORMAT_NO_CHANGE);
 | 
			
		||||
        argInput.setDefault(-1);
 | 
			
		||||
        argWidth.setDefault(-1);
 | 
			
		||||
        argHeight.setDefault(-1);
 | 
			
		||||
        argCropWidth.setDefault(0);
 | 
			
		||||
        argCropHeight.setDefault(0);
 | 
			
		||||
        argSizeDecimation.setDefault(1);
 | 
			
		||||
        argFrameDecimation.setDefault(1);
 | 
			
		||||
        argAddress.setDefault("127.0.0.1:19445");
 | 
			
		||||
        argPriority.setDefault(800);
 | 
			
		||||
        argSignalThreshold.setDefault(-1);
 | 
			
		||||
 | 
			
		||||
		// parse all options
 | 
			
		||||
		optionParser.parse(argc, const_cast<const char **>(argv));
 | 
			
		||||
        // parse all options
 | 
			
		||||
        optionParser.parse(argc, const_cast<const char **>(argv));
 | 
			
		||||
 | 
			
		||||
		// check if we need to display the usage. exit if we do.
 | 
			
		||||
		if (argHelp.isSet())
 | 
			
		||||
		{
 | 
			
		||||
			optionParser.usage();
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
        // check if we need to display the usage. exit if we do.
 | 
			
		||||
        if (argHelp.isSet())
 | 
			
		||||
        {
 | 
			
		||||
            optionParser.usage();
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		if (!argCropLeft.isSet())   argCropLeft.setDefault(argCropWidth.getValue());
 | 
			
		||||
		if (!argCropRight.isSet())  argCropRight.setDefault(argCropWidth.getValue());
 | 
			
		||||
		if (!argCropTop.isSet())    argCropTop.setDefault(argCropHeight.getValue());
 | 
			
		||||
		if (!argCropBottom.isSet()) argCropBottom.setDefault(argCropHeight.getValue());
 | 
			
		||||
        if (!argCropLeft.isSet())   argCropLeft.setDefault(argCropWidth.getValue());
 | 
			
		||||
        if (!argCropRight.isSet())  argCropRight.setDefault(argCropWidth.getValue());
 | 
			
		||||
        if (!argCropTop.isSet())    argCropTop.setDefault(argCropHeight.getValue());
 | 
			
		||||
        if (!argCropBottom.isSet()) argCropBottom.setDefault(argCropHeight.getValue());
 | 
			
		||||
 | 
			
		||||
		// initialize the grabber
 | 
			
		||||
		V4L2Grabber grabber(
 | 
			
		||||
					argDevice.getValue(),
 | 
			
		||||
					argInput.getValue(),
 | 
			
		||||
					argVideoStandard.getValue(),
 | 
			
		||||
					argPixelFormat.getValue(),
 | 
			
		||||
					argWidth.getValue(),
 | 
			
		||||
					argHeight.getValue(),
 | 
			
		||||
					std::max(1, argFrameDecimation.getValue()),
 | 
			
		||||
					std::max(1, argSizeDecimation.getValue()),
 | 
			
		||||
					std::max(1, argSizeDecimation.getValue()));
 | 
			
		||||
        // initialize the grabber
 | 
			
		||||
        V4L2Grabber grabber(
 | 
			
		||||
                    argDevice.getValue(),
 | 
			
		||||
                    argInput.getValue(),
 | 
			
		||||
                    argVideoStandard.getValue(),
 | 
			
		||||
                    argPixelFormat.getValue(),
 | 
			
		||||
                    argWidth.getValue(),
 | 
			
		||||
                    argHeight.getValue(),
 | 
			
		||||
                    std::max(1, argFrameDecimation.getValue()),
 | 
			
		||||
                    std::max(1, argSizeDecimation.getValue()),
 | 
			
		||||
                    std::max(1, argSizeDecimation.getValue()));
 | 
			
		||||
 | 
			
		||||
		// set signal detection
 | 
			
		||||
		grabber.setSignalThreshold(
 | 
			
		||||
					std::min(1.0, std::max(0.0, argRedSignalThreshold.isSet() ? argRedSignalThreshold.getValue() : argSignalThreshold.getValue())),
 | 
			
		||||
					std::min(1.0, std::max(0.0, argGreenSignalThreshold.isSet() ? argGreenSignalThreshold.getValue() : argSignalThreshold.getValue())),
 | 
			
		||||
					std::min(1.0, std::max(0.0, argBlueSignalThreshold.isSet() ? argBlueSignalThreshold.getValue() : argSignalThreshold.getValue())),
 | 
			
		||||
					50);
 | 
			
		||||
        // set signal detection
 | 
			
		||||
        grabber.setSignalThreshold(
 | 
			
		||||
                    std::min(1.0, std::max(0.0, argRedSignalThreshold.isSet() ? argRedSignalThreshold.getValue() : argSignalThreshold.getValue())),
 | 
			
		||||
                    std::min(1.0, std::max(0.0, argGreenSignalThreshold.isSet() ? argGreenSignalThreshold.getValue() : argSignalThreshold.getValue())),
 | 
			
		||||
                    std::min(1.0, std::max(0.0, argBlueSignalThreshold.isSet() ? argBlueSignalThreshold.getValue() : argSignalThreshold.getValue())),
 | 
			
		||||
                    50);
 | 
			
		||||
 | 
			
		||||
		// set cropping values
 | 
			
		||||
		grabber.setCropping(
 | 
			
		||||
					std::max(0, argCropLeft.getValue()),
 | 
			
		||||
					std::max(0, argCropRight.getValue()),
 | 
			
		||||
					std::max(0, argCropTop.getValue()),
 | 
			
		||||
					std::max(0, argCropBottom.getValue()));
 | 
			
		||||
        // set cropping values
 | 
			
		||||
        grabber.setCropping(
 | 
			
		||||
                    std::max(0, argCropLeft.getValue()),
 | 
			
		||||
                    std::max(0, argCropRight.getValue()),
 | 
			
		||||
                    std::max(0, argCropTop.getValue()),
 | 
			
		||||
                    std::max(0, argCropBottom.getValue()));
 | 
			
		||||
 | 
			
		||||
		// set 3D mode if applicable
 | 
			
		||||
		if (arg3DSBS.isSet())
 | 
			
		||||
		{
 | 
			
		||||
			grabber.set3D(VIDEO_3DSBS);
 | 
			
		||||
		}
 | 
			
		||||
		else if (arg3DTAB.isSet())
 | 
			
		||||
		{
 | 
			
		||||
			grabber.set3D(VIDEO_3DTAB);
 | 
			
		||||
		}
 | 
			
		||||
        // set 3D mode if applicable
 | 
			
		||||
        if (arg3DSBS.isSet())
 | 
			
		||||
        {
 | 
			
		||||
            grabber.set3D(VIDEO_3DSBS);
 | 
			
		||||
        }
 | 
			
		||||
        else if (arg3DTAB.isSet())
 | 
			
		||||
        {
 | 
			
		||||
            grabber.set3D(VIDEO_3DTAB);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		// run the grabber
 | 
			
		||||
		if (argScreenshot.isSet())
 | 
			
		||||
		{
 | 
			
		||||
			ScreenshotHandler handler("screenshot.png");
 | 
			
		||||
			QObject::connect(&grabber, SIGNAL(newFrame(Image<ColorRgb>)), &handler, SLOT(receiveImage(Image<ColorRgb>)));
 | 
			
		||||
			grabber.start();
 | 
			
		||||
			QCoreApplication::exec();
 | 
			
		||||
			grabber.stop();
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			ImageHandler handler(argAddress.getValue(), argPriority.getValue(), argSkipReply.isSet());
 | 
			
		||||
			QObject::connect(&grabber, SIGNAL(newFrame(Image<ColorRgb>)), &handler, SLOT(receiveImage(Image<ColorRgb>)));
 | 
			
		||||
			grabber.start();
 | 
			
		||||
			QCoreApplication::exec();
 | 
			
		||||
			grabber.stop();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	catch (const std::runtime_error & e)
 | 
			
		||||
	{
 | 
			
		||||
		// An error occured. Display error and quit
 | 
			
		||||
		std::cerr << e.what() << std::endl;
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
        // run the grabber
 | 
			
		||||
        if (argScreenshot.isSet())
 | 
			
		||||
        {
 | 
			
		||||
            ScreenshotHandler handler("screenshot.png");
 | 
			
		||||
            QObject::connect(&grabber, SIGNAL(newFrame(Image<ColorRgb>)), &handler, SLOT(receiveImage(Image<ColorRgb>)));
 | 
			
		||||
            grabber.start();
 | 
			
		||||
            QCoreApplication::exec();
 | 
			
		||||
            grabber.stop();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            ProtoConnectionWrapper handler(argAddress.getValue(), argPriority.getValue(), 1000, argSkipReply.isSet());
 | 
			
		||||
            QObject::connect(&grabber, SIGNAL(newFrame(Image<ColorRgb>)), &handler, SLOT(receiveImage(Image<ColorRgb>)));
 | 
			
		||||
            grabber.start();
 | 
			
		||||
            QCoreApplication::exec();
 | 
			
		||||
            grabber.stop();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    catch (const std::runtime_error & e)
 | 
			
		||||
    {
 | 
			
		||||
        // An error occured. Display error and quit
 | 
			
		||||
        std::cerr << e.what() << std::endl;
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,6 @@ cmake_minimum_required(VERSION 2.8)
 | 
			
		||||
# Set the project name
 | 
			
		||||
project(hyperion-x11)
 | 
			
		||||
 | 
			
		||||
# add protocol buffers
 | 
			
		||||
find_package(Protobuf REQUIRED)
 | 
			
		||||
 | 
			
		||||
# find Qt4
 | 
			
		||||
find_package(Qt4 REQUIRED QtCore QtGui QtNetwork)
 | 
			
		||||
 | 
			
		||||
@@ -14,42 +11,27 @@ find_package(Qt4 REQUIRED QtCore QtGui QtNetwork)
 | 
			
		||||
find_package(X11 REQUIRED)
 | 
			
		||||
 | 
			
		||||
include_directories(
 | 
			
		||||
	${CMAKE_CURRENT_BINARY_DIR}
 | 
			
		||||
	${PROTOBUF_INCLUDE_DIRS}
 | 
			
		||||
	${CMAKE_CURRENT_BINARY_DIR}/../../libsrc/protoserver
 | 
			
		||||
	${QT_INCLUDES}
 | 
			
		||||
	${X11_INCLUDES}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(Hyperion_X11_QT_HEADERS
 | 
			
		||||
	ProtoWrapper.h
 | 
			
		||||
	X11Wrapper.h)
 | 
			
		||||
 | 
			
		||||
set(Hyperion_X11_HEADERS
 | 
			
		||||
	X11Grabber.h
 | 
			
		||||
	../hyperion-v4l2/ProtoConnection.h
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(Hyperion_X11_SOURCES
 | 
			
		||||
	hyperion-x11.cpp
 | 
			
		||||
	ProtoWrapper.cpp
 | 
			
		||||
	X11Grabber.cpp
 | 
			
		||||
	X11Wrapper.cpp
 | 
			
		||||
	../hyperion-v4l2/ProtoConnection.cpp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(Hyperion_X11_PROTOS
 | 
			
		||||
	${CMAKE_CURRENT_SOURCE_DIR}/../../libsrc/protoserver/message.proto
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
QT4_WRAP_CPP(Hyperion_X11_HEADERS_MOC ${Hyperion_X11_QT_HEADERS})
 | 
			
		||||
 | 
			
		||||
protobuf_generate_cpp(Hyperion_X11_PROTO_SRCS Hyperion_X11_PROTO_HDRS ${Hyperion_X11_PROTOS})
 | 
			
		||||
 | 
			
		||||
add_executable(hyperion-x11
 | 
			
		||||
	${Hyperion_X11_HEADERS}
 | 
			
		||||
	${Hyperion_X11_SOURCES}
 | 
			
		||||
	${Hyperion_X11_PROTO_SRCS}
 | 
			
		||||
	${Hyperion_X11_PROTO_HDRS}
 | 
			
		||||
	${Hyperion_X11_HEADERS_MOC}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -57,7 +39,8 @@ target_link_libraries(hyperion-x11
 | 
			
		||||
	getoptPlusPlus
 | 
			
		||||
	blackborder
 | 
			
		||||
	hyperion-utils
 | 
			
		||||
	${PROTOBUF_LIBRARIES}
 | 
			
		||||
	protoserver
 | 
			
		||||
	x11-grabber
 | 
			
		||||
	${X11_LIBRARIES}
 | 
			
		||||
	pthread
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +0,0 @@
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
#include "ProtoWrapper.h"
 | 
			
		||||
 | 
			
		||||
ProtoWrapper::ProtoWrapper(const std::string & protoAddress, const bool skipReply) :
 | 
			
		||||
	_priority(10),
 | 
			
		||||
	_duration_ms(2000),
 | 
			
		||||
	_connection(protoAddress)
 | 
			
		||||
{
 | 
			
		||||
	_connection.setSkipReply(skipReply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ProtoWrapper::process(const Image<ColorRgb> & image)
 | 
			
		||||
{
 | 
			
		||||
	std::cout << "Attempt to send screenshot" << std::endl;
 | 
			
		||||
	_connection.setImage(image, _priority, _duration_ms);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,23 +0,0 @@
 | 
			
		||||
 | 
			
		||||
// QT includes
 | 
			
		||||
#include <QObject>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "../hyperion-v4l2/ProtoConnection.h"
 | 
			
		||||
 | 
			
		||||
class ProtoWrapper : public QObject
 | 
			
		||||
{
 | 
			
		||||
	Q_OBJECT
 | 
			
		||||
public:
 | 
			
		||||
	ProtoWrapper(const std::string & protoAddress, const bool skipReply);
 | 
			
		||||
 | 
			
		||||
public slots:
 | 
			
		||||
	void process(const Image<ColorRgb> & image);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
	int _priority;
 | 
			
		||||
	int _duration_ms;
 | 
			
		||||
 | 
			
		||||
	ProtoConnection _connection;
 | 
			
		||||
};
 | 
			
		||||
@@ -1,115 +0,0 @@
 | 
			
		||||
// STL includes
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
 | 
			
		||||
// X11 includes
 | 
			
		||||
#include <X11/Xutil.h>
 | 
			
		||||
 | 
			
		||||
// X11Grabber includes
 | 
			
		||||
#include "X11Grabber.h"
 | 
			
		||||
 | 
			
		||||
X11Grabber::X11Grabber(const unsigned cropHorizontal, const unsigned cropVertical, const unsigned pixelDecimation) :
 | 
			
		||||
	_pixelDecimation(pixelDecimation),
 | 
			
		||||
	_cropWidth(cropHorizontal),
 | 
			
		||||
	_cropHeight(cropVertical),
 | 
			
		||||
	_x11Display(nullptr),
 | 
			
		||||
	_screenWidth(0),
 | 
			
		||||
	_screenHeight(0),
 | 
			
		||||
	_image(0,0)
 | 
			
		||||
{
 | 
			
		||||
	// empty
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
X11Grabber::~X11Grabber()
 | 
			
		||||
{
 | 
			
		||||
	if (_x11Display != nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		XCloseDisplay(_x11Display);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int X11Grabber::open()
 | 
			
		||||
{
 | 
			
		||||
	const char * display_name = nullptr;
 | 
			
		||||
	_x11Display = XOpenDisplay(display_name);
 | 
			
		||||
 | 
			
		||||
	if (_x11Display == nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		std::cerr << "Failed to open the default X11-display" << std::endl;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Image<ColorRgb> & X11Grabber::grab()
 | 
			
		||||
{
 | 
			
		||||
	if (_x11Display == nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		open();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	updateScreenDimensions();
 | 
			
		||||
 | 
			
		||||
	const int croppedWidth  = _screenWidth  - 2*_cropWidth;
 | 
			
		||||
	const int croppedHeight = _screenHeight - 2*_cropHeight;
 | 
			
		||||
 | 
			
		||||
	// Capture the current screen
 | 
			
		||||
	XImage * xImage = XGetImage(_x11Display, DefaultRootWindow(_x11Display), _cropWidth, _cropHeight, croppedWidth, croppedHeight, AllPlanes, ZPixmap);
 | 
			
		||||
	if (xImage == nullptr)
 | 
			
		||||
	{
 | 
			
		||||
		std::cerr << "Grab failed" << std::endl;
 | 
			
		||||
		return _image;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Copy the capture XImage to the local image (and apply required decimation)
 | 
			
		||||
	ColorRgb * outputPtr = _image.memptr();
 | 
			
		||||
	for (int iY=(_pixelDecimation/2); iY<croppedHeight; iY+=_pixelDecimation)
 | 
			
		||||
	{
 | 
			
		||||
		for (int iX=(_pixelDecimation/2); iX<croppedWidth; iX+=_pixelDecimation)
 | 
			
		||||
		{
 | 
			
		||||
			// Extract the pixel from the X11-image
 | 
			
		||||
			const uint32_t pixel = uint32_t(XGetPixel(xImage, iX, iY));
 | 
			
		||||
 | 
			
		||||
			// Assign the color value
 | 
			
		||||
			outputPtr->red   = uint8_t((pixel >> 16) & 0xff);
 | 
			
		||||
			outputPtr->green = uint8_t((pixel >> 8)  & 0xff);
 | 
			
		||||
			outputPtr->blue  = uint8_t((pixel >> 0)  & 0xff);
 | 
			
		||||
 | 
			
		||||
			// Move to the next output pixel
 | 
			
		||||
			++outputPtr;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// Cleanup allocated resources of the X11 grab
 | 
			
		||||
	XDestroyImage(xImage);
 | 
			
		||||
 | 
			
		||||
	return _image;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int X11Grabber::updateScreenDimensions()
 | 
			
		||||
{
 | 
			
		||||
	XWindowAttributes window_attributes_return;
 | 
			
		||||
	const Status status = XGetWindowAttributes(_x11Display, DefaultRootWindow(_x11Display), &window_attributes_return);
 | 
			
		||||
	if (status == 0)
 | 
			
		||||
	{
 | 
			
		||||
		std::cerr << "Failed to obtain window attributes" << std::endl;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (_screenWidth == unsigned(window_attributes_return.width) && _screenHeight == unsigned(window_attributes_return.height))
 | 
			
		||||
	{
 | 
			
		||||
		// No update required
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
	std::cout << "Update of screen resolution: [" << _screenWidth << "x" << _screenHeight <<"] => ";
 | 
			
		||||
	_screenWidth  = window_attributes_return.width;
 | 
			
		||||
	_screenHeight = window_attributes_return.height;
 | 
			
		||||
	std::cout << "[" << _screenWidth << "x" << _screenHeight <<"]" << std::endl;
 | 
			
		||||
 | 
			
		||||
	// Update the size of the buffer used to transfer the screenshot
 | 
			
		||||
	int width  = (_screenWidth  - 2 * _cropWidth  + _pixelDecimation/2) / _pixelDecimation;
 | 
			
		||||
	int height = (_screenHeight - 2 * _cropHeight + _pixelDecimation/2) / _pixelDecimation;
 | 
			
		||||
	_image.resize(width, height);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -3,31 +3,31 @@
 | 
			
		||||
#include "X11Wrapper.h"
 | 
			
		||||
 | 
			
		||||
X11Wrapper::X11Wrapper(const unsigned cropHorizontal, const unsigned cropVertical, const unsigned pixelDecimation) :
 | 
			
		||||
	_timer(this),
 | 
			
		||||
	_grabber(cropHorizontal, cropVertical, pixelDecimation)
 | 
			
		||||
    _timer(this),
 | 
			
		||||
    _grabber(cropHorizontal, cropVertical, pixelDecimation)
 | 
			
		||||
{
 | 
			
		||||
	// Connect capturing to the timeout signal of the timer
 | 
			
		||||
	connect(&_timer, SIGNAL(timeout()), this, SLOT(capture()));
 | 
			
		||||
    // Connect capturing to the timeout signal of the timer
 | 
			
		||||
    connect(&_timer, SIGNAL(timeout()), this, SLOT(capture()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Image<ColorRgb> & X11Wrapper::getScreenshot()
 | 
			
		||||
{
 | 
			
		||||
	const Image<ColorRgb> & screenshot = _grabber.grab();
 | 
			
		||||
	return screenshot;
 | 
			
		||||
    const Image<ColorRgb> & screenshot = _grabber.grab();
 | 
			
		||||
    return screenshot;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void X11Wrapper::start()
 | 
			
		||||
{
 | 
			
		||||
	_timer.start(200);
 | 
			
		||||
    _timer.start(100);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void X11Wrapper::stop()
 | 
			
		||||
{
 | 
			
		||||
	_timer.stop();
 | 
			
		||||
    _timer.stop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void X11Wrapper::capture()
 | 
			
		||||
{
 | 
			
		||||
	const Image<ColorRgb> & screenshot = _grabber.grab();
 | 
			
		||||
	emit sig_screenshot(screenshot);
 | 
			
		||||
    const Image<ColorRgb> & screenshot = _grabber.grab();
 | 
			
		||||
    emit sig_screenshot(screenshot);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,37 +3,37 @@
 | 
			
		||||
#include <QTimer>
 | 
			
		||||
 | 
			
		||||
// Hyperion-X11 includes
 | 
			
		||||
#include "X11Grabber.h"
 | 
			
		||||
#include <grabber/X11Grabber.h>
 | 
			
		||||
 | 
			
		||||
class X11Wrapper : public QObject
 | 
			
		||||
{
 | 
			
		||||
	Q_OBJECT
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
public:
 | 
			
		||||
	X11Wrapper(const unsigned cropHorizontal, const unsigned cropVertical, const unsigned pixelDecimation);
 | 
			
		||||
    X11Wrapper(const unsigned cropHorizontal, const unsigned cropVertical, const unsigned pixelDecimation);
 | 
			
		||||
 | 
			
		||||
	const Image<ColorRgb> & getScreenshot();
 | 
			
		||||
    const Image<ColorRgb> & getScreenshot();
 | 
			
		||||
 | 
			
		||||
	///
 | 
			
		||||
	/// Starts the timed capturing of screenshots
 | 
			
		||||
	///
 | 
			
		||||
	void start();
 | 
			
		||||
    ///
 | 
			
		||||
    /// Starts the timed capturing of screenshots
 | 
			
		||||
    ///
 | 
			
		||||
    void start();
 | 
			
		||||
 | 
			
		||||
	void stop();
 | 
			
		||||
    void stop();
 | 
			
		||||
 | 
			
		||||
signals:
 | 
			
		||||
	void sig_screenshot(const Image<ColorRgb> & screenshot);
 | 
			
		||||
    void sig_screenshot(const Image<ColorRgb> & screenshot);
 | 
			
		||||
 | 
			
		||||
private slots:
 | 
			
		||||
	///
 | 
			
		||||
	/// Performs a single screenshot capture and publishes the capture screenshot on the screenshot
 | 
			
		||||
	/// signal.
 | 
			
		||||
	///
 | 
			
		||||
	void capture();
 | 
			
		||||
    ///
 | 
			
		||||
    /// Performs a single screenshot capture and publishes the capture screenshot on the screenshot
 | 
			
		||||
    /// signal.
 | 
			
		||||
    ///
 | 
			
		||||
    void capture();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	/// The QT timer to generate capture-publish events
 | 
			
		||||
	QTimer _timer;
 | 
			
		||||
    /// The QT timer to generate capture-publish events
 | 
			
		||||
    QTimer _timer;
 | 
			
		||||
 | 
			
		||||
	/// The grabber for creating screenshots
 | 
			
		||||
	X11Grabber _grabber;
 | 
			
		||||
    /// The grabber for creating screenshots
 | 
			
		||||
    X11Grabber _grabber;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
// getoptPlusPLus includes
 | 
			
		||||
#include <getoptPlusPlus/getoptpp.h>
 | 
			
		||||
 | 
			
		||||
#include "ProtoWrapper.h"
 | 
			
		||||
#include "protoserver/ProtoConnectionWrapper.h"
 | 
			
		||||
#include "X11Wrapper.h"
 | 
			
		||||
 | 
			
		||||
using namespace vlofgren;
 | 
			
		||||
@@ -14,77 +14,77 @@ using namespace vlofgren;
 | 
			
		||||
// save the image as screenshot
 | 
			
		||||
void saveScreenshot(const char * filename, const Image<ColorRgb> & image)
 | 
			
		||||
{
 | 
			
		||||
	// store as PNG
 | 
			
		||||
	QImage pngImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888);
 | 
			
		||||
	pngImage.save(filename);
 | 
			
		||||
    // store as PNG
 | 
			
		||||
    QImage pngImage((const uint8_t *) image.memptr(), image.width(), image.height(), 3*image.width(), QImage::Format_RGB888);
 | 
			
		||||
    pngImage.save(filename);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char ** argv)
 | 
			
		||||
{
 | 
			
		||||
	QCoreApplication app(argc, argv);
 | 
			
		||||
    QCoreApplication app(argc, argv);
 | 
			
		||||
 | 
			
		||||
	try
 | 
			
		||||
	{
 | 
			
		||||
		// create the option parser and initialize all parameters
 | 
			
		||||
		OptionsParser optionParser("X11 capture application for Hyperion");
 | 
			
		||||
		ParameterSet & parameters = optionParser.getParameters();
 | 
			
		||||
    try
 | 
			
		||||
    {
 | 
			
		||||
        // create the option parser and initialize all parameters
 | 
			
		||||
        OptionsParser optionParser("X11 capture application for Hyperion");
 | 
			
		||||
        ParameterSet & parameters = optionParser.getParameters();
 | 
			
		||||
 | 
			
		||||
		IntParameter           & argCropWidth       = parameters.add<IntParameter>          (0x0, "crop-width",       "Number of pixels to crop from the left and right sides in 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 in the picture before decimation [default=0]");
 | 
			
		||||
		IntParameter           & argSizeDecimation  = parameters.add<IntParameter>          ('s', "size-decimator",   "Decimation factor for the output size [default=16]");
 | 
			
		||||
		SwitchParameter<>      & argScreenshot      = parameters.add<SwitchParameter<>>     (0x0, "screenshot",       "Take a single screenshot, save it to file and quit");
 | 
			
		||||
		StringParameter        & argAddress         = parameters.add<StringParameter>       ('a', "address",          "Set the address of the hyperion server [default: 127.0.0.1:19445]");
 | 
			
		||||
		IntParameter           & argPriority        = parameters.add<IntParameter>          ('p', "priority",         "Use the provided priority channel (the lower the number, the higher the priority) [default: 800]");
 | 
			
		||||
		SwitchParameter<>      & argSkipReply       = parameters.add<SwitchParameter<>>     (0x0, "skip-reply",       "Do not receive and check reply messages from Hyperion");
 | 
			
		||||
		SwitchParameter<>      & argHelp            = parameters.add<SwitchParameter<>>     ('h', "help",             "Show this help message and exit");
 | 
			
		||||
        IntParameter           & argCropWidth       = parameters.add<IntParameter>          (0x0, "crop-width",       "Number of pixels to crop from the left and right sides in 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 in the picture before decimation [default=0]");
 | 
			
		||||
        IntParameter           & argSizeDecimation  = parameters.add<IntParameter>          ('s', "size-decimator",   "Decimation factor for the output size [default=16]");
 | 
			
		||||
        SwitchParameter<>      & argScreenshot      = parameters.add<SwitchParameter<>>     (0x0, "screenshot",       "Take a single screenshot, save it to file and quit");
 | 
			
		||||
        StringParameter        & argAddress         = parameters.add<StringParameter>       ('a', "address",          "Set the address of the hyperion server [default: 127.0.0.1:19445]");
 | 
			
		||||
        IntParameter           & argPriority        = parameters.add<IntParameter>          ('p', "priority",         "Use the provided priority channel (the lower the number, the higher the priority) [default: 800]");
 | 
			
		||||
        SwitchParameter<>      & argSkipReply       = parameters.add<SwitchParameter<>>     (0x0, "skip-reply",       "Do not receive and check reply messages from Hyperion");
 | 
			
		||||
        SwitchParameter<>      & argHelp            = parameters.add<SwitchParameter<>>     ('h', "help",             "Show this help message and exit");
 | 
			
		||||
 | 
			
		||||
		// set defaults
 | 
			
		||||
		argCropWidth.setDefault(0);
 | 
			
		||||
		argCropHeight.setDefault(0);
 | 
			
		||||
		argSizeDecimation.setDefault(16);
 | 
			
		||||
		argAddress.setDefault("127.0.0.1:19445");
 | 
			
		||||
		argPriority.setDefault(800);
 | 
			
		||||
        // set defaults
 | 
			
		||||
        argCropWidth.setDefault(0);
 | 
			
		||||
        argCropHeight.setDefault(0);
 | 
			
		||||
        argSizeDecimation.setDefault(16);
 | 
			
		||||
        argAddress.setDefault("127.0.0.1:19445");
 | 
			
		||||
        argPriority.setDefault(800);
 | 
			
		||||
 | 
			
		||||
		// parse all options
 | 
			
		||||
		optionParser.parse(argc, const_cast<const char **>(argv));
 | 
			
		||||
        // parse all options
 | 
			
		||||
        optionParser.parse(argc, const_cast<const char **>(argv));
 | 
			
		||||
 | 
			
		||||
		// check if we need to display the usage. exit if we do.
 | 
			
		||||
		if (argHelp.isSet())
 | 
			
		||||
		{
 | 
			
		||||
			optionParser.usage();
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
        // check if we need to display the usage. exit if we do.
 | 
			
		||||
        if (argHelp.isSet())
 | 
			
		||||
        {
 | 
			
		||||
            optionParser.usage();
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		// Create the X11 grabbing stuff
 | 
			
		||||
		X11Wrapper x11Wrapper(argCropWidth.getValue(), argCropHeight.getValue(), argSizeDecimation.getValue());
 | 
			
		||||
        // Create the X11 grabbing stuff
 | 
			
		||||
        X11Wrapper x11Wrapper(argCropWidth.getValue(), argCropHeight.getValue(), argSizeDecimation.getValue());
 | 
			
		||||
 | 
			
		||||
		if (argScreenshot.isSet())
 | 
			
		||||
		{
 | 
			
		||||
			// Capture a single screenshot and finish
 | 
			
		||||
			const Image<ColorRgb> & screenshot = x11Wrapper.getScreenshot();
 | 
			
		||||
			saveScreenshot("screenshot.png", screenshot);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			// Create the Proto-connection with hyperiond
 | 
			
		||||
			ProtoWrapper protoWrapper(argAddress.getValue(), argSkipReply.isSet());
 | 
			
		||||
        if (argScreenshot.isSet())
 | 
			
		||||
        {
 | 
			
		||||
            // Capture a single screenshot and finish
 | 
			
		||||
            const Image<ColorRgb> & screenshot = x11Wrapper.getScreenshot();
 | 
			
		||||
            saveScreenshot("screenshot.png", screenshot);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            // Create the Proto-connection with hyperiond
 | 
			
		||||
            ProtoConnectionWrapper protoWrapper(argAddress.getValue(), argPriority.getValue(), 1000, argSkipReply.isSet());
 | 
			
		||||
 | 
			
		||||
			// Connect the screen capturing to the proto processing
 | 
			
		||||
			QObject::connect(&x11Wrapper, SIGNAL(sig_screenshot(const Image<ColorRgb> &)), &protoWrapper, SLOT(process(Image<ColorRgb>)));
 | 
			
		||||
            // Connect the screen capturing to the proto processing
 | 
			
		||||
            QObject::connect(&x11Wrapper, SIGNAL(sig_screenshot(const Image<ColorRgb> &)), &protoWrapper, SLOT(process(Image<ColorRgb>)));
 | 
			
		||||
 | 
			
		||||
			// Start the capturing
 | 
			
		||||
			x11Wrapper.start();
 | 
			
		||||
            // Start the capturing
 | 
			
		||||
            x11Wrapper.start();
 | 
			
		||||
 | 
			
		||||
			// Start the application
 | 
			
		||||
			app.exec();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	catch (const std::runtime_error & e)
 | 
			
		||||
	{
 | 
			
		||||
		// An error occured. Display error and quit
 | 
			
		||||
		std::cerr << e.what() << std::endl;
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
            // Start the application
 | 
			
		||||
            app.exec();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    catch (const std::runtime_error & e)
 | 
			
		||||
    {
 | 
			
		||||
        // An error occured. Display error and quit
 | 
			
		||||
        std::cerr << e.what() << std::endl;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user