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

View File

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

View File

@ -59,10 +59,9 @@ V4L2Grabber::V4L2Grabber(
_frameDecimation(std::max(1, frameDecimation)),
_horizontalPixelDecimation(std::max(1, horizontalPixelDecimation)),
_verticalPixelDecimation(std::max(1, verticalPixelDecimation)),
_mode3D(MODE_NONE),
_mode3D(VIDEO_2D),
_currentFrame(0),
_callback(nullptr),
_callbackArg(nullptr)
_streamNotifier(nullptr)
{
open_device();
init_device(videoStandard, input);
@ -82,66 +81,21 @@ void V4L2Grabber::setCropping(int cropLeft, int cropRight, int cropTop, int crop
_cropBottom = cropBottom;
}
void V4L2Grabber::set3D(Mode3D mode)
void V4L2Grabber::set3D(VideoMode mode)
{
_mode3D = mode;
}
void V4L2Grabber::setCallback(V4L2Grabber::ImageCallback callback, void *arg)
{
_callback = callback;
_callbackArg = arg;
}
void V4L2Grabber::start()
{
_streamNotifier->setEnabled(true);
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()
{
stop_capturing();
_streamNotifier->setEnabled(false);
}
void V4L2Grabber::open_device()
@ -170,6 +124,10 @@ void V4L2Grabber::open_device()
oss << "Cannot open '" << _deviceName << "'";
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()
@ -178,6 +136,12 @@ void V4L2Grabber::close_device()
throw_errno_exception("close");
_fileDescriptor = -1;
if (_streamNotifier != nullptr)
{
delete _streamNotifier;
_streamNotifier = nullptr;
}
}
void V4L2Grabber::init_read(unsigned int buffer_size)
@ -674,10 +638,10 @@ void V4L2Grabber::process_image(const uint8_t * data)
switch (_mode3D)
{
case MODE_3DSBS:
case VIDEO_3DSBS:
width = _width/2;
break;
case MODE_3DTAB:
case VIDEO_3DTAB:
height = _height/2;
break;
default:
@ -717,10 +681,7 @@ void V4L2Grabber::process_image(const uint8_t * data)
}
}
if (_callback != nullptr)
{
(*_callback)(_callbackArg, image);
}
emit newFrame(image);
}
int V4L2Grabber::xioctl(int request, void *arg)

View File

@ -14,16 +14,21 @@ include_directories(
${QT_INCLUDES}
)
set(Hyperion_V4L2_HEADERS
ProtoConnection.h
set(Hyperion_V4L2_QT_HEADERS
ImageHandler.h
ScreenshotHandler.h
)
set(Hyperion_V4L2_HEADERS
VideoStandardParameter.h
ProtoConnection.h
)
set(Hyperion_V4L2_SOURCES
hyperion-v4l2.cpp
ProtoConnection.cpp
ImageHandler.cpp
ScreenshotHandler.cpp
)
set(Hyperion_V4L2_PROTOS
@ -34,9 +39,13 @@ 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
${Hyperion_V4L2_HEADERS}
${Hyperion_V4L2_SOURCES}
${Hyperion_V4L2_QT_HEADERS}
${Hyperion_V4L2_MOC_SOURCES}
${Hyperion_V4L2_PROTO_SRCS}
${Hyperion_V4L2_PROTO_HDRS}
)
@ -48,5 +57,5 @@ target_link_libraries(hyperion-v4l2
hyperion-utils
${PROTOBUF_LIBRARIES}
pthread
${QT_LIBRARIES}
${QT_LIBRARIES}
)

View File

@ -10,6 +10,10 @@ ImageHandler::ImageHandler(const std::string & address, int priority, double sig
_connection.setSkipReply(skipProtoReply);
}
ImageHandler::~ImageHandler()
{
}
void ImageHandler::receiveImage(const Image<ColorRgb> & image)
{
// 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
#include <blackborder/BlackBorderProcessor.h>
// hyperion-v4l includes
// hyperion v4l2 includes
#include "ProtoConnection.h"
/// This class handles callbacks from the V4L2 grabber
class ImageHandler
class ImageHandler : public QObject
{
Q_OBJECT
public:
ImageHandler(const std::string & address, int priority, double signalThreshold, bool skipProtoReply);
virtual ~ImageHandler();
public slots:
/// Handle a single image
/// @param image The image to process
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:
/// Priority for calls to Hyperion
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>
// QT includes
#include <QImage>
#include <QCoreApplication>
// getoptPlusPLus includes
#include <getoptPlusPlus/getoptpp.h>
@ -19,6 +19,7 @@
#include "ProtoConnection.h"
#include "VideoStandardParameter.h"
#include "ImageHandler.h"
#include "ScreenshotHandler.h"
using namespace vlofgren;
@ -32,8 +33,11 @@ void saveScreenshot(void *, const Image<ColorRgb> & image)
int main(int argc, char** argv)
{
QCoreApplication app(argc, argv);
// force the locale
setlocale(LC_ALL, "C");
QLocale::setDefault(QLocale::c());
try
{
@ -113,31 +117,30 @@ int main(int argc, char** argv)
// set 3D mode if applicable
if (arg3DSBS.isSet())
{
grabber.set3D(V4L2Grabber::MODE_3DSBS);
grabber.set3D(VIDEO_3DSBS);
}
else if (arg3DTAB.isSet())
{
grabber.set3D(V4L2Grabber::MODE_3DTAB);
grabber.set3D(VIDEO_3DTAB);
}
// start the grabber
grabber.start();
// run the grabber
if (argScreenshot.isSet())
{
grabber.setCallback(&saveScreenshot, nullptr);
grabber.capture(1);
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(), argSignalThreshold.getValue(), argSkipReply.isSet());
grabber.setCallback(&ImageHandler::imageCallback, &handler);
grabber.capture();
QObject::connect(&grabber, SIGNAL(newFrame(Image<ColorRgb>)), &handler, SLOT(receiveImage(Image<ColorRgb>)));
grabber.start();
QCoreApplication::exec();
grabber.stop();
}
// stop the grabber
grabber.stop();
}
catch (const std::runtime_error & e)
{