Create image callback using Qt signal

Former-commit-id: cf469ba01ffd26d286e6fb8d9f081cf126042e50
This commit is contained in:
johan 2014-02-19 21:52:37 +01:00
parent f0c35071da
commit 69d6e47328
9 changed files with 141 additions and 106 deletions

View File

@ -4,26 +4,27 @@
#include <string> #include <string>
#include <vector> #include <vector>
// Qt includes
#include <QObject>
#include <QSocketNotifier>
// util includes // util includes
#include <utils/Image.h> #include <utils/Image.h>
#include <utils/ColorRgb.h> #include <utils/ColorRgb.h>
#include <utils/VideoMode.h>
/// Capture class for V4L2 devices /// Capture class for V4L2 devices
/// ///
/// @see http://linuxtv.org/downloads/v4l-dvb-apis/capture-example.html /// @see http://linuxtv.org/downloads/v4l-dvb-apis/capture-example.html
class V4L2Grabber class V4L2Grabber : public QObject
{ {
public: Q_OBJECT
typedef void (*ImageCallback)(void * arg, const Image<ColorRgb> & image);
public:
enum VideoStandard { enum VideoStandard {
PAL, NTSC, NO_CHANGE PAL, NTSC, NO_CHANGE
}; };
enum Mode3D {
MODE_NONE, MODE_3DSBS, MODE_3DTAB
};
public: public:
V4L2Grabber( V4L2Grabber(
const std::string & device, const std::string & device,
@ -36,21 +37,24 @@ public:
int verticalPixelDecimation); int verticalPixelDecimation);
virtual ~V4L2Grabber(); virtual ~V4L2Grabber();
public slots:
void setCropping(int cropLeft, void setCropping(int cropLeft,
int cropRight, int cropRight,
int cropTop, int cropTop,
int cropBottom); int cropBottom);
void set3D(Mode3D mode); void set3D(VideoMode mode);
void setCallback(ImageCallback callback, void * arg);
void start(); void start();
void capture(int frameCount = -1);
void stop(); void stop();
signals:
void newFrame(const Image<ColorRgb> & image);
private slots:
int read_frame();
private: private:
void open_device(); void open_device();
@ -70,8 +74,6 @@ private:
void stop_capturing(); void stop_capturing();
int read_frame();
bool process_image(const void *p, int size); bool process_image(const void *p, int size);
void process_image(const uint8_t *p); void process_image(const uint8_t *p);
@ -111,10 +113,9 @@ private:
int _horizontalPixelDecimation; int _horizontalPixelDecimation;
int _verticalPixelDecimation; int _verticalPixelDecimation;
Mode3D _mode3D; VideoMode _mode3D;
int _currentFrame; int _currentFrame;
ImageCallback _callback; QSocketNotifier * _streamNotifier;
void * _callbackArg;
}; };

View File

@ -2,18 +2,27 @@
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber) SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber)
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/v4l2) SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/grabber/v4l2)
SET(V4L2_HEADERS SET(V4L2_QT_HEADERS
${CURRENT_HEADER_DIR}/V4L2Grabber.h ${CURRENT_HEADER_DIR}/V4L2Grabber.h
) )
SET(V4L2_HEADERS
)
SET(V4L2_SOURCES SET(V4L2_SOURCES
${CURRENT_SOURCE_DIR}/V4L2Grabber.cpp ${CURRENT_SOURCE_DIR}/V4L2Grabber.cpp
) )
QT4_WRAP_CPP(V4L2_HEADERS_MOC ${V4L2_QT_HEADERS})
add_library(v4l2-grabber add_library(v4l2-grabber
${V4L2_HEADERS} ${V4L2_HEADERS}
${V4L2_SOURCES} ${V4L2_SOURCES}
${V4L2_QT_HEADERS}
${V4L2_HEADERS_MOC}
) )
target_link_libraries(v4l2-grabber target_link_libraries(v4l2-grabber
hyperion-utils) hyperion
${QT_LIBRARIES}
)

View File

@ -59,10 +59,9 @@ V4L2Grabber::V4L2Grabber(
_frameDecimation(std::max(1, frameDecimation)), _frameDecimation(std::max(1, frameDecimation)),
_horizontalPixelDecimation(std::max(1, horizontalPixelDecimation)), _horizontalPixelDecimation(std::max(1, horizontalPixelDecimation)),
_verticalPixelDecimation(std::max(1, verticalPixelDecimation)), _verticalPixelDecimation(std::max(1, verticalPixelDecimation)),
_mode3D(MODE_NONE), _mode3D(VIDEO_2D),
_currentFrame(0), _currentFrame(0),
_callback(nullptr), _streamNotifier(nullptr)
_callbackArg(nullptr)
{ {
open_device(); open_device();
init_device(videoStandard, input); init_device(videoStandard, input);
@ -82,66 +81,21 @@ void V4L2Grabber::setCropping(int cropLeft, int cropRight, int cropTop, int crop
_cropBottom = cropBottom; _cropBottom = cropBottom;
} }
void V4L2Grabber::set3D(Mode3D mode) void V4L2Grabber::set3D(VideoMode mode)
{ {
_mode3D = mode; _mode3D = mode;
} }
void V4L2Grabber::setCallback(V4L2Grabber::ImageCallback callback, void *arg)
{
_callback = callback;
_callbackArg = arg;
}
void V4L2Grabber::start() void V4L2Grabber::start()
{ {
_streamNotifier->setEnabled(true);
start_capturing(); start_capturing();
} }
void V4L2Grabber::capture(int frameCount)
{
for (int count = 0; count < frameCount || frameCount < 0; ++count)
{
for (;;)
{
// the set of file descriptors for select
fd_set fds;
FD_ZERO(&fds);
FD_SET(_fileDescriptor, &fds);
// timeout
struct timeval tv;
tv.tv_sec = 2;
tv.tv_usec = 0;
// block until data is available
int r = select(_fileDescriptor + 1, &fds, NULL, NULL, &tv);
if (-1 == r)
{
if (EINTR == errno)
continue;
throw_errno_exception("select");
}
if (0 == r)
{
throw_exception("select timeout");
}
if (read_frame())
{
break;
}
/* EAGAIN - continue select loop. */
}
}
}
void V4L2Grabber::stop() void V4L2Grabber::stop()
{ {
stop_capturing(); stop_capturing();
_streamNotifier->setEnabled(false);
} }
void V4L2Grabber::open_device() void V4L2Grabber::open_device()
@ -170,6 +124,10 @@ void V4L2Grabber::open_device()
oss << "Cannot open '" << _deviceName << "'"; oss << "Cannot open '" << _deviceName << "'";
throw_errno_exception(oss.str()); throw_errno_exception(oss.str());
} }
// create the notifier for when a new frame is available
_streamNotifier = new QSocketNotifier(_fileDescriptor, QSocketNotifier::Read);
connect(_streamNotifier, SIGNAL(activated(int)), this, SLOT(read_frame()));
} }
void V4L2Grabber::close_device() void V4L2Grabber::close_device()
@ -178,6 +136,12 @@ void V4L2Grabber::close_device()
throw_errno_exception("close"); throw_errno_exception("close");
_fileDescriptor = -1; _fileDescriptor = -1;
if (_streamNotifier != nullptr)
{
delete _streamNotifier;
_streamNotifier = nullptr;
}
} }
void V4L2Grabber::init_read(unsigned int buffer_size) void V4L2Grabber::init_read(unsigned int buffer_size)
@ -674,10 +638,10 @@ void V4L2Grabber::process_image(const uint8_t * data)
switch (_mode3D) switch (_mode3D)
{ {
case MODE_3DSBS: case VIDEO_3DSBS:
width = _width/2; width = _width/2;
break; break;
case MODE_3DTAB: case VIDEO_3DTAB:
height = _height/2; height = _height/2;
break; break;
default: default:
@ -717,10 +681,7 @@ void V4L2Grabber::process_image(const uint8_t * data)
} }
} }
if (_callback != nullptr) emit newFrame(image);
{
(*_callback)(_callbackArg, image);
}
} }
int V4L2Grabber::xioctl(int request, void *arg) int V4L2Grabber::xioctl(int request, void *arg)

View File

@ -14,16 +14,21 @@ include_directories(
${QT_INCLUDES} ${QT_INCLUDES}
) )
set(Hyperion_V4L2_HEADERS set(Hyperion_V4L2_QT_HEADERS
ProtoConnection.h
ImageHandler.h ImageHandler.h
ScreenshotHandler.h
)
set(Hyperion_V4L2_HEADERS
VideoStandardParameter.h VideoStandardParameter.h
ProtoConnection.h
) )
set(Hyperion_V4L2_SOURCES set(Hyperion_V4L2_SOURCES
hyperion-v4l2.cpp hyperion-v4l2.cpp
ProtoConnection.cpp ProtoConnection.cpp
ImageHandler.cpp ImageHandler.cpp
ScreenshotHandler.cpp
) )
set(Hyperion_V4L2_PROTOS set(Hyperion_V4L2_PROTOS
@ -34,9 +39,13 @@ protobuf_generate_cpp(Hyperion_V4L2_PROTO_SRCS Hyperion_V4L2_PROTO_HDRS
${Hyperion_V4L2_PROTOS} ${Hyperion_V4L2_PROTOS}
) )
QT4_WRAP_CPP(Hyperion_V4L2_MOC_SOURCES ${Hyperion_V4L2_QT_HEADERS})
add_executable(hyperion-v4l2 add_executable(hyperion-v4l2
${Hyperion_V4L2_HEADERS} ${Hyperion_V4L2_HEADERS}
${Hyperion_V4L2_SOURCES} ${Hyperion_V4L2_SOURCES}
${Hyperion_V4L2_QT_HEADERS}
${Hyperion_V4L2_MOC_SOURCES}
${Hyperion_V4L2_PROTO_SRCS} ${Hyperion_V4L2_PROTO_SRCS}
${Hyperion_V4L2_PROTO_HDRS} ${Hyperion_V4L2_PROTO_HDRS}
) )

View File

@ -10,6 +10,10 @@ ImageHandler::ImageHandler(const std::string & address, int priority, double sig
_connection.setSkipReply(skipProtoReply); _connection.setSkipReply(skipProtoReply);
} }
ImageHandler::~ImageHandler()
{
}
void ImageHandler::receiveImage(const Image<ColorRgb> & image) void ImageHandler::receiveImage(const Image<ColorRgb> & image)
{ {
// check if we should do signal detection // check if we should do signal detection
@ -32,10 +36,3 @@ void ImageHandler::receiveImage(const Image<ColorRgb> & image)
} }
} }
} }
void ImageHandler::imageCallback(void *arg, const Image<ColorRgb> &image)
{
ImageHandler * handler = static_cast<ImageHandler *>(arg);
handler->receiveImage(image);
}

View File

@ -1,24 +1,30 @@
// Qt includes
#include <QObject>
// hyperion includes
#include <utils/Image.h>
#include <utils/ColorRgb.h>
// blackborder includes // blackborder includes
#include <blackborder/BlackBorderProcessor.h> #include <blackborder/BlackBorderProcessor.h>
// hyperion-v4l includes // hyperion v4l2 includes
#include "ProtoConnection.h" #include "ProtoConnection.h"
/// This class handles callbacks from the V4L2 grabber /// This class handles callbacks from the V4L2 grabber
class ImageHandler class ImageHandler : public QObject
{ {
Q_OBJECT
public: public:
ImageHandler(const std::string & address, int priority, double signalThreshold, bool skipProtoReply); ImageHandler(const std::string & address, int priority, double signalThreshold, bool skipProtoReply);
virtual ~ImageHandler();
public slots:
/// Handle a single image /// Handle a single image
/// @param image The image to process /// @param image The image to process
void receiveImage(const Image<ColorRgb> & image); void receiveImage(const Image<ColorRgb> & image);
/// static function used to direct callbacks to a ImageHandler object
/// @param arg This should be an ImageHandler instance
/// @param image The image to process
static void imageCallback(void * arg, const Image<ColorRgb> & image);
private: private:
/// Priority for calls to Hyperion /// Priority for calls to Hyperion
const int _priority; const int _priority;

View File

@ -0,0 +1,25 @@
// Qt includes
#include <QImage>
#include <QCoreApplication>
// hyperion-v4l2 includes
#include "ScreenshotHandler.h"
ScreenshotHandler::ScreenshotHandler(const std::string & filename) :
_filename(filename)
{
}
ScreenshotHandler::~ScreenshotHandler()
{
}
void ScreenshotHandler::receiveImage(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.c_str());
// Quit the application after the first image
QCoreApplication::quit();
}

View File

@ -0,0 +1,24 @@
// Qt includes
#include <QObject>
// hyperionincludes
#include <utils/Image.h>
#include <utils/ColorRgb.h>
/// This class handles callbacks from the V4L2 grabber
class ScreenshotHandler : public QObject
{
Q_OBJECT
public:
ScreenshotHandler(const std::string & filename);
virtual ~ScreenshotHandler();
public slots:
/// Handle a single image
/// @param image The image to process
void receiveImage(const Image<ColorRgb> & image);
private:
const std::string _filename;
};

View File

@ -4,7 +4,7 @@
#include <clocale> #include <clocale>
// QT includes // QT includes
#include <QImage> #include <QCoreApplication>
// getoptPlusPLus includes // getoptPlusPLus includes
#include <getoptPlusPlus/getoptpp.h> #include <getoptPlusPlus/getoptpp.h>
@ -19,6 +19,7 @@
#include "ProtoConnection.h" #include "ProtoConnection.h"
#include "VideoStandardParameter.h" #include "VideoStandardParameter.h"
#include "ImageHandler.h" #include "ImageHandler.h"
#include "ScreenshotHandler.h"
using namespace vlofgren; using namespace vlofgren;
@ -32,8 +33,11 @@ void saveScreenshot(void *, const Image<ColorRgb> & image)
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
QCoreApplication app(argc, argv);
// force the locale // force the locale
setlocale(LC_ALL, "C"); setlocale(LC_ALL, "C");
QLocale::setDefault(QLocale::c());
try try
{ {
@ -113,32 +117,31 @@ int main(int argc, char** argv)
// set 3D mode if applicable // set 3D mode if applicable
if (arg3DSBS.isSet()) if (arg3DSBS.isSet())
{ {
grabber.set3D(V4L2Grabber::MODE_3DSBS); grabber.set3D(VIDEO_3DSBS);
} }
else if (arg3DTAB.isSet()) else if (arg3DTAB.isSet())
{ {
grabber.set3D(V4L2Grabber::MODE_3DTAB); grabber.set3D(VIDEO_3DTAB);
} }
// start the grabber
grabber.start();
// run the grabber // run the grabber
if (argScreenshot.isSet()) if (argScreenshot.isSet())
{ {
grabber.setCallback(&saveScreenshot, nullptr); ScreenshotHandler handler("screenshot.png");
grabber.capture(1); QObject::connect(&grabber, SIGNAL(newFrame(Image<ColorRgb>)), &handler, SLOT(receiveImage(Image<ColorRgb>)));
grabber.start();
QCoreApplication::exec();
grabber.stop();
} }
else else
{ {
ImageHandler handler(argAddress.getValue(), argPriority.getValue(), argSignalThreshold.getValue(), argSkipReply.isSet()); ImageHandler handler(argAddress.getValue(), argPriority.getValue(), argSignalThreshold.getValue(), argSkipReply.isSet());
grabber.setCallback(&ImageHandler::imageCallback, &handler); QObject::connect(&grabber, SIGNAL(newFrame(Image<ColorRgb>)), &handler, SLOT(receiveImage(Image<ColorRgb>)));
grabber.capture(); grabber.start();
} QCoreApplication::exec();
// stop the grabber
grabber.stop(); grabber.stop();
} }
}
catch (const std::runtime_error & e) catch (const std::runtime_error & e)
{ {
// An error occured. Display error and quit // An error occured. Display error and quit