grabber api and feature unification (#462)

* move setvideomode to common place

* implement more croping and 3d support

* more api unification

* more refactoring

* osx fix

* next step

* add a mock for osx grabber. Now it is possible to test compile on none osx platforms.

* more unifications ...

* remove obsolete includes and grabbers are not dyn allocated. dispmanx needs rework an probaly not work atm

* first version of dispmanx mock. it compiles, but outputs a black image

* now dispmanx mock works!

* activate mocks in travis linux build
prepare dispmanx to rgb image out

* dispmanx now with image rgb output
fix deadlock with w/h -1 in grabber v4l
cleanups

* fix json

* fix some runtime stuff

* Update FramebufferWrapper.cpp

fix missing code

* unify grabframe

* 3d and croping for amlogic

* fix setimage not working

* make use of templates
save some codelines

* save more code lines
This commit is contained in:
redPanther
2017-08-12 07:55:32 +02:00
committed by GitHub
parent 317a903b14
commit 9eff6384cc
61 changed files with 830 additions and 748 deletions

View File

@@ -52,10 +52,6 @@ AmlogicGrabber::~AmlogicGrabber()
bool AmlogicGrabber::isVideoPlaying()
{
// TODO crop resulting image accroding member _videoMode
// TODO add croping
const QString videoDevice = "/dev/amvideo";
// Open the video device
@@ -81,13 +77,10 @@ bool AmlogicGrabber::isVideoPlaying()
return videoDisabled == 0;
}
int AmlogicGrabber::grabFrame(Image<ColorBgr> & image)
int AmlogicGrabber::grabFrame(Image<ColorRgb> & image)
{
// resize the given image if needed
if (image.width() != (unsigned)_width || image.height() != (unsigned)_height)
{
image.resize(_width, _height);
}
// TODO crop resulting image accroding member _videoMode
// TODO add croping
// Make sure video is playing, else there is nothing to grab
if (!isVideoPlaying())
@@ -95,7 +88,6 @@ int AmlogicGrabber::grabFrame(Image<ColorBgr> & image)
return -1;
}
// If the device is not open, attempt to open it
if (_amlogicCaptureDev == -1)
{
@@ -121,7 +113,7 @@ int AmlogicGrabber::grabFrame(Image<ColorBgr> & image)
}
// Read the snapshot into the memory
void * image_ptr = image.memptr();
void * image_ptr = _image.memptr();
const ssize_t bytesToRead = _width * _height * sizeof(ColorBgr);
const ssize_t bytesRead = pread(_amlogicCaptureDev, image_ptr, bytesToRead, 0);
@@ -150,5 +142,10 @@ int AmlogicGrabber::grabFrame(Image<ColorBgr> & image)
_amlogicCaptureDev = -1;
readCnt = 0;
}
_imageResampler.setHorizontalPixelDecimation(_width);
_imageResampler.setVerticalPixelDecimation(_height);
_imageResampler.processImage((const uint8_t*)image_ptr, _width, _height, 3, PIXELFORMAT_BGR24, image);
return 0;
}

View File

@@ -1,53 +1,11 @@
// QT includes
#include <QDateTime>
// Hyperion includes
#include <hyperion/Hyperion.h>
#include <hyperion/ImageProcessorFactory.h>
#include <hyperion/ImageProcessor.h>
// Amlogic grabber includes
#include <grabber/AmlogicWrapper.h>
#include <grabber/AmlogicGrabber.h>
AmlogicWrapper::AmlogicWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, const int priority)
: GrabberWrapper("AmLogic", priority)
, _updateInterval_ms(1000/updateRate_Hz)
, _timeout_ms(2 * _updateInterval_ms)
, _image(grabWidth, grabHeight)
, _grabber(new AmlogicGrabber(grabWidth, grabHeight))
, _ledColors(Hyperion::getInstance()->getLedCount(), ColorRgb{0,0,0})
{
// Configure the timer to generate events every n milliseconds
_timer.setInterval(_updateInterval_ms);
_processor->setSize(grabWidth, grabHeight);
}
AmlogicWrapper::~AmlogicWrapper()
{
delete _grabber;
}
: GrabberWrapper("AmLogic", &_grabber, grabWidth, grabHeight, updateRate_Hz, priority, hyperion::COMP_GRABBER)
, _grabber(grabWidth, grabHeight)
{}
void AmlogicWrapper::action()
{
// Grab frame into the allocated image
if (_grabber->grabFrame(_image) < 0)
{
// Frame grab failed, maybe nothing playing or ....
return;
}
Image<ColorRgb> image_rgb;
_image.toRgb(image_rgb);
emit emitImage(_priority, image_rgb, _timeout_ms);
_processor->process(_image, _ledColors);
setColors(_ledColors, _timeout_ms);
}
void AmlogicWrapper::setVideoMode(const VideoMode mode)
{
_grabber->setVideoMode(mode);
transferFrame(_grabber);
}

View File

@@ -1,6 +1,11 @@
# Find the BCM-package (VC control)
find_package(BCM REQUIRED)
include_directories(${BCM_INCLUDE_DIRS})
IF ( "${PLATFORM}" MATCHES rpi)
find_package(BCM REQUIRED)
include_directories(${BCM_INCLUDE_DIRS})
ELSE()
SET(BCM_INCLUDE_DIRS "")
SET(BCM_LIBRARIES "")
ENDIF()
# Define the current source locations
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/grabber)

View File

@@ -13,7 +13,10 @@ DispmanxFrameGrabber::DispmanxFrameGrabber(const unsigned width, const unsigned
, _vc_flags(0)
, _captureBuffer(new ColorRgba[0])
, _captureBufferSize(0)
, _image_rgba(width, height)
{
_useImageResampler = false;
// Initiase BCM
bcm_host_init();
@@ -64,33 +67,15 @@ void DispmanxFrameGrabber::setFlags(const int vc_flags)
_vc_flags = vc_flags;
}
void DispmanxFrameGrabber::setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom)
{
if (cropLeft + cropRight >= (unsigned)_width || cropTop + cropBottom >= (unsigned)_height)
{
Error(_log, "Rejecting invalid crop values: left: %d, right: %d, top: %d, bottom: %d", cropLeft, cropRight, cropTop, cropBottom);
return;
}
_cropLeft = cropLeft;
_cropRight = cropRight;
_cropTop = cropTop;
_cropBottom = cropBottom;
if (cropLeft > 0 || cropRight > 0 || cropTop > 0 || cropBottom > 0)
{
Info(_log, "Cropping image: width=%d height=%d; crop: left=%d right=%d top=%d bottom=%d ", _width, _height, cropLeft, cropRight, cropTop, cropBottom);
}
}
void DispmanxFrameGrabber::grabFrame(Image<ColorRgba> & image)
int DispmanxFrameGrabber::grabFrame(Image<ColorRgb> & image)
{
int ret;
// vc_dispmanx_resource_read_data doesn't seem to work well
// with arbitrary positions so we have to handle cropping by ourselves
unsigned cropLeft = _cropLeft;
unsigned cropRight = _cropRight;
unsigned cropTop = _cropTop;
unsigned cropLeft = _cropLeft;
unsigned cropRight = _cropRight;
unsigned cropTop = _cropTop;
unsigned cropBottom = _cropBottom;
if (_vc_flags & DISPMANX_SNAPSHOT_FILL)
@@ -99,19 +84,19 @@ void DispmanxFrameGrabber::grabFrame(Image<ColorRgba> & image)
cropLeft = cropRight = cropTop = cropBottom = 0;
}
unsigned imageWidth = _width - cropLeft - cropRight;
unsigned imageWidth = _width - cropLeft - cropRight;
unsigned imageHeight = _height - cropTop - cropBottom;
// calculate final image dimensions and adjust top/left cropping in 3D modes
switch (_videoMode)
{
case VIDEO_3DSBS:
imageWidth = imageWidth / 2;
cropLeft = cropLeft / 2;
imageWidth /= 2;
cropLeft /= 2;
break;
case VIDEO_3DTAB:
imageHeight = imageHeight / 2;
cropTop = cropTop / 2;
imageHeight /= 2;
cropTop /= 2;
break;
case VIDEO_2D:
default:
@@ -124,12 +109,17 @@ void DispmanxFrameGrabber::grabFrame(Image<ColorRgba> & image)
image.resize(imageWidth, imageHeight);
}
if (_image_rgba.width() != imageWidth || _image_rgba.height() != imageHeight)
{
_image_rgba.resize(imageWidth, imageHeight);
}
// Open the connection to the display
_vc_display = vc_dispmanx_display_open(0);
if (_vc_display < 0)
{
Error(_log, "Cannot open display: %d", _vc_display);
return;
return -1;
}
// Create the snapshot (incl down-scaling)
@@ -138,11 +128,11 @@ void DispmanxFrameGrabber::grabFrame(Image<ColorRgba> & image)
{
Error(_log, "Snapshot failed: %d", ret);
vc_dispmanx_display_close(_vc_display);
return;
return ret;
}
// Read the snapshot into the memory
void* imagePtr = image.memptr();
void* imagePtr = _image_rgba.memptr();
void* capturePtr = imagePtr;
unsigned imagePitch = imageWidth * sizeof(ColorRgba);
@@ -172,7 +162,7 @@ void DispmanxFrameGrabber::grabFrame(Image<ColorRgba> & image)
{
Error(_log, "vc_dispmanx_resource_read_data failed: %d", ret);
vc_dispmanx_display_close(_vc_display);
return;
return ret;
}
// copy capture data to image if we captured to temp buffer
@@ -193,4 +183,9 @@ void DispmanxFrameGrabber::grabFrame(Image<ColorRgba> & image)
// Close the displaye
vc_dispmanx_display_close(_vc_display);
// image to output image
_image_rgba.toRgb(image);
return 0;
}

View File

@@ -0,0 +1,107 @@
#ifndef PLATFORM_RPI
#include <grabber/DispmanxFrameGrabberMock.h>
unsigned __bcm_frame_counter = 0;
const int __screenWidth = 800;
const int __screenHeight = 600;
void bcm_host_init()
{
}
void bcm_host_deinit()
{
}
int vc_dispmanx_display_open(int)
{
return 1;
}
void vc_dispmanx_display_close(int)
{
}
int vc_dispmanx_display_get_info(int, DISPMANX_MODEINFO_T *vc_info)
{
vc_info->width = __screenWidth;
vc_info->height = __screenHeight;
return 0;
}
DISPMANX_RESOURCE_HANDLE_T vc_dispmanx_resource_create(int,int width,int height, uint32_t *)
{
return new DISPMANX_RESOURCE(width,height);
}
void vc_dispmanx_resource_delete(DISPMANX_RESOURCE_HANDLE_T resource)
{
delete resource;
}
int vc_dispmanx_resource_read_data(DISPMANX_RESOURCE_HANDLE_T resource, VC_RECT_T *rectangle, void* capturePtr, unsigned capturePitch)
{
memcpy(capturePtr, resource->memptr(), resource->height()*resource->width() * sizeof(ColorRgba));
return 0;
}
void vc_dispmanx_rect_set(VC_RECT_T *rectangle, int left, int top, int width, int height)
{
rectangle->width = width;
rectangle->height = height;
rectangle->left = left;
rectangle->top = top;
}
int vc_dispmanx_snapshot(int, DISPMANX_RESOURCE_HANDLE_T resource, int vc_flags)
{
__bcm_frame_counter++;
if (__bcm_frame_counter > 100)
{
__bcm_frame_counter = 0;
}
ColorRgba color[4] = {ColorRgba::RED, ColorRgba::BLUE, ColorRgba::GREEN, ColorRgba::WHITE};
if (__bcm_frame_counter < 25)
{
color[0] = ColorRgba::WHITE;
color[1] = ColorRgba::RED;
color[2] = ColorRgba::BLUE;
color[3] = ColorRgba::GREEN;
}
else if(__bcm_frame_counter < 50)
{
color[1] = ColorRgba::WHITE;
color[2] = ColorRgba::RED;
color[3] = ColorRgba::BLUE;
color[0] = ColorRgba::GREEN;
}
else if(__bcm_frame_counter < 75)
{
color[2] = ColorRgba::WHITE;
color[3] = ColorRgba::RED;
color[0] = ColorRgba::BLUE;
color[1] = ColorRgba::GREEN;
}
unsigned w = resource->width();
unsigned h = resource->height();
for (unsigned y=0; y<h; y++)
{
for (unsigned x=0; x<w; x++)
{
unsigned id = 0;
if (x < w/2 && y < h/2) id = 1;
if (x < w/2 && y >= h/2) id = 2;
if (x >= w/2 && y < h/2) id = 3;
resource->memptr()[y*w + x] = color[id];
}
}
return 0;
}
#endif

View File

@@ -1,56 +1,13 @@
// QT includes
#include <QDateTime>
// Hyperion includes
#include <hyperion/Hyperion.h>
#include <hyperion/ImageProcessorFactory.h>
#include <hyperion/ImageProcessor.h>
// Dispmanx grabber includes
#include <grabber/DispmanxWrapper.h>
#include <grabber/DispmanxFrameGrabber.h>
DispmanxWrapper::DispmanxWrapper(const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, const int priority)
: GrabberWrapper("Dispmanx", priority)
, _updateInterval_ms(1000/updateRate_Hz)
, _timeout_ms(2 * _updateInterval_ms)
, _image(grabWidth, grabHeight)
, _grabber(new DispmanxFrameGrabber(grabWidth, grabHeight))
, _ledColors(Hyperion::getInstance()->getLedCount(), ColorRgb{0,0,0})
: GrabberWrapper("Dispmanx", &_grabber, grabWidth, grabHeight, updateRate_Hz, priority, hyperion::COMP_GRABBER)
, _grabber(grabWidth, grabHeight)
{
// Configure the timer to generate events every n milliseconds
_timer.setInterval(_updateInterval_ms);
_processor->setSize(grabWidth, grabHeight);
}
DispmanxWrapper::~DispmanxWrapper()
{
delete _grabber;
setImageProcessorEnabled(false);
}
void DispmanxWrapper::action()
{
// Grab frame into the allocated image
_grabber->grabFrame(_image);
Image<ColorRgb> image_rgb;
_image.toRgb(image_rgb);
emit emitImage(_priority, image_rgb, _timeout_ms);
_processor->process(_image, _ledColors);
setColors(_ledColors, _timeout_ms);
}
void DispmanxWrapper::setVideoMode(const VideoMode mode)
{
_grabber->setVideoMode(mode);
}
void DispmanxWrapper::setCropping(const unsigned cropLeft, const unsigned cropRight,
const unsigned cropTop, const unsigned cropBottom)
{
_grabber->setCropping(cropLeft, cropRight, cropTop, cropBottom);
transferFrame(_grabber);
}

View File

@@ -47,7 +47,7 @@ FramebufferFrameGrabber::~FramebufferFrameGrabber()
{
}
void FramebufferFrameGrabber::grabFrame(Image<ColorRgb> & image)
int FramebufferFrameGrabber::grabFrame(Image<ColorRgb> & image)
{
struct fb_var_screeninfo vinfo;
unsigned capSize, bytesPerPixel;
@@ -62,25 +62,17 @@ void FramebufferFrameGrabber::grabFrame(Image<ColorRgb> & image)
bytesPerPixel = vinfo.bits_per_pixel / 8;
capSize = vinfo.xres * vinfo.yres * bytesPerPixel;
if (vinfo.bits_per_pixel == 16)
switch (vinfo.bits_per_pixel)
{
pixelFormat = PIXELFORMAT_BGR16;
case 16: pixelFormat = PIXELFORMAT_BGR16; break;
case 24: pixelFormat = PIXELFORMAT_BGR24; break;
case 32: pixelFormat = PIXELFORMAT_BGR32; break;
default:
Error(_log, "Unknown pixel format: %d bits per pixel", vinfo.bits_per_pixel);
close(_fbfd);
return -1;
}
else if (vinfo.bits_per_pixel == 24)
{
pixelFormat = PIXELFORMAT_BGR24;
}
else if (vinfo.bits_per_pixel == 32)
{
pixelFormat = PIXELFORMAT_BGR32;
}
else
{
Error(_log, "Unknown pixel format: %d bits per pixel", vinfo.bits_per_pixel);
close(_fbfd);
return;
}
/* map the device to memory */
_fbp = (unsigned char*)mmap(0, capSize, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, _fbfd, 0);
@@ -95,4 +87,6 @@ void FramebufferFrameGrabber::grabFrame(Image<ColorRgb> & image)
munmap(_fbp, capSize);
close(_fbfd);
return 0;
}

View File

@@ -1,43 +1,11 @@
// Hyperion includes
#include <hyperion/Hyperion.h>
#include <hyperion/ImageProcessorFactory.h>
#include <hyperion/ImageProcessor.h>
// Framebuffer grabber includes
#include <grabber/FramebufferWrapper.h>
#include <grabber/FramebufferFrameGrabber.h>
FramebufferWrapper::FramebufferWrapper(const QString & device, const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, const int priority)
: GrabberWrapper("FrameBuffer", priority)
, _updateInterval_ms(1000/updateRate_Hz)
, _timeout_ms(2 * _updateInterval_ms)
, _image(grabWidth, grabHeight)
, _grabber(new FramebufferFrameGrabber(device, grabWidth, grabHeight))
, _ledColors(Hyperion::getInstance()->getLedCount(), ColorRgb{0,0,0})
{
// Configure the timer to generate events every n milliseconds
_timer.setInterval(_updateInterval_ms);
_processor->setSize(grabWidth, grabHeight);
}
FramebufferWrapper::~FramebufferWrapper()
{
delete _grabber;
}
: GrabberWrapper("FrameBuffer", &_grabber, grabWidth, grabHeight, updateRate_Hz, priority, hyperion::COMP_GRABBER)
, _grabber(device, grabWidth, grabHeight)
{}
void FramebufferWrapper::action()
{
// Grab frame into the allocated image
_grabber->grabFrame(_image);
emit emitImage(_priority, _image, _timeout_ms);
_processor->process(_image, _ledColors);
setColors(_ledColors, _timeout_ms);
}
void FramebufferWrapper::setVideoMode(const VideoMode mode)
{
_grabber->setVideoMode(mode);
transferFrame(_grabber);
}

View File

@@ -19,7 +19,9 @@ OsxFrameGrabber::OsxFrameGrabber(const unsigned display, const unsigned width, c
{
Error(_log, "Display with index %d is not available. Using main display", _screenIndex);
_display = kCGDirectMainDisplay;
} else {
}
else
{
_display = displays[_screenIndex];
}
@@ -35,7 +37,7 @@ OsxFrameGrabber::~OsxFrameGrabber()
{
}
void OsxFrameGrabber::grabFrame(Image<ColorRgb> & image)
int OsxFrameGrabber::grabFrame(Image<ColorRgb> & image)
{
CGImageRef dispImage;
CFDataRef imgData;
@@ -52,12 +54,12 @@ void OsxFrameGrabber::grabFrame(Image<ColorRgb> & image)
if (dispImage == NULL)
{
Error(_log, "No display connected...");
return;
return -1;
}
}
imgData = CGDataProviderCopyData(CGImageGetDataProvider(dispImage));
pImgData = (unsigned char*) CFDataGetBytePtr(imgData);
dspWidth = CGImageGetWidth(dispImage);
imgData = CGDataProviderCopyData(CGImageGetDataProvider(dispImage));
pImgData = (unsigned char*) CFDataGetBytePtr(imgData);
dspWidth = CGImageGetWidth(dispImage);
dspHeight = CGImageGetHeight(dispImage);
_imageResampler.setHorizontalPixelDecimation(dspWidth/_width);
@@ -71,4 +73,6 @@ void OsxFrameGrabber::grabFrame(Image<ColorRgb> & image)
CFRelease(imgData);
CGImageRelease(dispImage);
return 0;
}

View File

@@ -0,0 +1,126 @@
#ifndef __APPLE__
#include <grabber/OsxFrameGrabberMock.h>
unsigned __osx_frame_counter = 0;
const int __screenWidth = 800;
const int __screenHeight = 600;
void CGGetActiveDisplayList(int max, CGDirectDisplayID *displays, CGDisplayCount *displayCount)
{
*displayCount = 1;
displays[0] = 1;
}
CGImageRef CGDisplayCreateImage(CGDirectDisplayID display)
{
CGImageRef image = new CGImage(__screenWidth, __screenHeight);
return image;
}
void CGImageRelease(CGImageRef image)
{
delete image;
}
CGImageRef CGImageGetDataProvider(CGImageRef image)
{
__osx_frame_counter++;
if (__osx_frame_counter > 100)
{
__osx_frame_counter = 0;
}
ColorRgb color[4] = {ColorRgb::RED, ColorRgb::BLUE, ColorRgb::GREEN, ColorRgb::WHITE};
if (__osx_frame_counter < 25)
{
color[0] = ColorRgb::WHITE;
color[1] = ColorRgb::RED;
color[2] = ColorRgb::BLUE;
color[3] = ColorRgb::GREEN;
}
else if(__osx_frame_counter < 50)
{
color[1] = ColorRgb::WHITE;
color[2] = ColorRgb::RED;
color[3] = ColorRgb::BLUE;
color[0] = ColorRgb::GREEN;
}
else if(__osx_frame_counter < 75)
{
color[2] = ColorRgb::WHITE;
color[3] = ColorRgb::RED;
color[0] = ColorRgb::BLUE;
color[1] = ColorRgb::GREEN;
}
unsigned w = image->width();
unsigned h = image->height();
for (unsigned y=0; y<h; y++)
{
for (unsigned x=0; x<w; x++)
{
unsigned id = 0;
if (x < w/2 && y < h/2) id = 1;
if (x < w/2 && y >= h/2) id = 2;
if (x >= w/2 && y < h/2) id = 3;
image->memptr()[y*w + x] = color[id];
}
}
return image;
}
CFDataRef CGDataProviderCopyData(CGImageRef image)
{
const unsigned indexMax = image->width() * image->height() * CGImageGetBitsPerPixel(image);
CFDataRef data = new CFData[indexMax];
int lineLength = CGImageGetBytesPerRow(image);
for (unsigned y=0; y<image->height(); y++)
{
for (unsigned x=0; x<image->width(); x++)
{
int index = lineLength * y + x * CGImageGetBitsPerPixel(image);
data[index ] = (*image)(x,y).blue;
data[index+1] = (*image)(x,y).green;
data[index+2] = (*image)(x,y).red;
data[index+3] = 0;
}
}
return data;
}
unsigned char* CFDataGetBytePtr(CFDataRef imgData)
{
return imgData;
}
unsigned CGImageGetWidth(CGImageRef image)
{
return image->width();
}
unsigned CGImageGetHeight(CGImageRef image)
{
return image->height();
}
unsigned CGImageGetBytesPerRow(CGImageRef image)
{
return image->width()*CGImageGetBitsPerPixel(image);
}
unsigned CGImageGetBitsPerPixel(CGImageRef)
{
return 4;
}
void CFRelease(CFDataRef imgData)
{
delete imgData;
}
#endif

View File

@@ -1,44 +1,11 @@
// Hyperion includes
#include <hyperion/Hyperion.h>
#include <hyperion/ImageProcessorFactory.h>
#include <hyperion/ImageProcessor.h>
// Osx grabber includes
#include <grabber/OsxWrapper.h>
#include <grabber/OsxFrameGrabber.h>
OsxWrapper::OsxWrapper(const unsigned display, const unsigned grabWidth, const unsigned grabHeight, const unsigned updateRate_Hz, const int priority)
: GrabberWrapper("OSX FrameGrabber", priority)
, _updateInterval_ms(1000/updateRate_Hz)
, _timeout_ms(2 * _updateInterval_ms)
, _image(grabWidth, grabHeight)
, _grabber(new OsxFrameGrabber(display, grabWidth, grabHeight))
, _ledColors(Hyperion::getInstance()->getLedCount(), ColorRgb{0,0,0})
{
// Configure the timer to generate events every n milliseconds
_timer.setInterval(_updateInterval_ms);
_processor->setSize(grabWidth, grabHeight);
}
OsxWrapper::~OsxWrapper()
{
delete _grabber;
}
: GrabberWrapper("OSX FrameGrabber", &_grabber, grabWidth, grabHeight, updateRate_Hz, priority, hyperion::COMP_GRABBER)
, _grabber(display, grabWidth, grabHeight)
{}
void OsxWrapper::action()
{
// Grab frame into the allocated image
_grabber->grabFrame(_image);
emit emitImage(_priority, _image, _timeout_ms);
_processor->process(_image, _ledColors);
setColors(_ledColors, _timeout_ms);
}
void OsxWrapper::setVideoMode(const VideoMode mode)
{
_grabber->setVideoMode(mode);
transferFrame(_grabber);
}

View File

@@ -27,8 +27,8 @@ V4L2Grabber::V4L2Grabber(const QString & device
, int input
, VideoStandard videoStandard
, PixelFormat pixelFormat
, int width
, int height
, unsigned width
, unsigned height
, int frameDecimation
, int horizontalPixelDecimation
, int verticalPixelDecimation
@@ -180,11 +180,6 @@ void V4L2Grabber::getV4Ldevices()
}
}
void V4L2Grabber::setCropping(int cropLeft, int cropRight, int cropTop, int cropBottom)
{
_imageResampler.setCropping(cropLeft, cropRight, cropTop, cropBottom);
}
void V4L2Grabber::setSignalThreshold(double redSignalThreshold, double greenSignalThreshold, double blueSignalThreshold, int noSignalCounterThreshold)
{
_noSignalThresholdColor.red = uint8_t(255*redSignalThreshold);

View File

@@ -8,8 +8,8 @@ V4L2Wrapper::V4L2Wrapper(const QString &device,
int input,
VideoStandard videoStandard,
PixelFormat pixelFormat,
int width,
int height,
unsigned width,
unsigned height,
int frameDecimation,
int pixelDecimation,
double redSignalThreshold,
@@ -17,8 +17,7 @@ V4L2Wrapper::V4L2Wrapper(const QString &device,
double blueSignalThreshold,
const int priority,
bool useGrabbingMode)
: GrabberWrapper("V4L2:"+device, priority, hyperion::COMP_V4L)
, _timeout_ms(1000)
: GrabberWrapper("V4L2:"+device, &_grabber, width, height, 8, priority, hyperion::COMP_V4L)
, _grabber(device,
input,
videoStandard,
@@ -28,10 +27,10 @@ V4L2Wrapper::V4L2Wrapper(const QString &device,
frameDecimation,
pixelDecimation,
pixelDecimation)
, _ledColors(Hyperion::getInstance()->getLedCount(), ColorRgb{0,0,0})
{
// set the signal detection threshold of the grabber
_grabber.setSignalThreshold( redSignalThreshold, greenSignalThreshold, blueSignalThreshold, 50);
_ggrabber = &_grabber;
// register the image type
qRegisterMetaType<Image<ColorRgb>>("Image<ColorRgb>");
@@ -40,29 +39,15 @@ V4L2Wrapper::V4L2Wrapper(const QString &device,
// Handle the image in the captured thread using a direct connection
QObject::connect(&_grabber, SIGNAL(newFrame(Image<ColorRgb>)), this, SLOT(newFrame(Image<ColorRgb>)), Qt::DirectConnection);
QObject::connect(&_grabber, SIGNAL(readError(const char*)), this, SLOT(readError(const char*)), Qt::DirectConnection);
if (!useGrabbingMode)
{
disconnect(_hyperion, SIGNAL(grabbingMode(GrabbingMode)), this, 0);
}
// send color data to Hyperion using a queued connection to handle the data over to the main event loop
// QObject::connect(
// this, SIGNAL(emitColors(int,std::vector<ColorRgb>,int)),
// _hyperion, SLOT(setColors(int,std::vector<ColorRgb>,int)),
// Qt::QueuedConnection);
// setup the higher prio source checker
// this will disable the v4l2 grabber when a source with higher priority is active
_timer.setInterval(500);
}
V4L2Wrapper::~V4L2Wrapper()
{
}
bool V4L2Wrapper::start()
{
return ( _grabber.start() && GrabberWrapper::start());
@@ -84,12 +69,6 @@ void V4L2Wrapper::setSignalDetectionOffset(double verticalMin, double horizontal
_grabber.setSignalDetectionOffset(verticalMin, horizontalMin, verticalMax, horizontalMax);
}
void V4L2Wrapper::setVideoMode(VideoMode mode)
{
_grabber.setVideoMode(mode);
}
void V4L2Wrapper::newFrame(const Image<ColorRgb> &image)
{
emit emitImage(_priority, image, _timeout_ms);

View File

@@ -14,8 +14,11 @@ X11Grabber::X11Grabber(bool useXGetImage, int cropLeft, int cropRight, int cropT
, _verticalDecimation(verticalPixelDecimation)
, _screenWidth(0)
, _screenHeight(0)
, _src_x(cropLeft)
, _src_y(cropTop)
, _image(0,0)
{
_useImageResampler = false;
_imageResampler.setCropping(0, 0, 0, 0); // cropping is performed by XRender, XShmGetImage or XGetImage
memset(&_pictAttr, 0, sizeof(_pictAttr));
_pictAttr.repeat = RepeatNone;
@@ -52,9 +55,7 @@ void X11Grabber::setupResources()
{
if(_XShmAvailable && !_useXGetImage)
{
_xImage = XShmCreateImage(_x11Display, _windowAttr.visual,
_windowAttr.depth, ZPixmap, NULL, &_shminfo,
_width, _height);
_xImage = XShmCreateImage(_x11Display, _windowAttr.visual, _windowAttr.depth, ZPixmap, NULL, &_shminfo, _width, _height);
_shminfo.shmid = shmget(IPC_PRIVATE, _xImage->bytes_per_line * _xImage->height, IPC_CREAT|0777);
_xImage->data = (char*)shmat(_shminfo.shmid,0,0);
_shminfo.shmaddr = _xImage->data;
@@ -109,13 +110,16 @@ bool X11Grabber::Setup()
_imageResampler.setHorizontalPixelDecimation(_XRenderAvailable ? 1 : _horizontalDecimation);
_imageResampler.setVerticalPixelDecimation(_XRenderAvailable ? 1 : _verticalDecimation);
return true;
bool result = (updateScreenDimensions(true) >=0);
ErrorIf(!result, _log, "X11 Grabber start failed");
return result;
}
Image<ColorRgb> & X11Grabber::grab()
int X11Grabber::grabFrame(Image<ColorRgb> & image, bool forceUpdate)
{
updateScreenDimensions();
if (forceUpdate)
updateScreenDimensions(forceUpdate);
if (_XRenderAvailable && !_useXGetImage)
{
double scale_x = static_cast<double>(_windowAttr.width / _horizontalDecimation) / static_cast<double>(_windowAttr.width);
@@ -145,19 +149,11 @@ Image<ColorRgb> & X11Grabber::grab()
XRenderSetPictureTransform (_x11Display, _srcPicture, &_transform);
XRenderComposite( _x11Display, // dpy
PictOpSrc, // op
_srcPicture, // src
None, // mask
_dstPicture, // dst
_cropLeft / _horizontalDecimation, // src_x _cropLeft
_cropTop / _verticalDecimation, // src_y _cropTop
0, // mask_x
0, // mask_y
0, // dst_x
0, // dst_y
_width, // width
_height); // height
// display, op, src, mask, dest, src_x = cropLeft,
// src_y = cropTop, mask_x, mask_y, dest_x, dest_y, width, height
XRenderComposite(
_x11Display, PictOpSrc, _srcPicture, None, _dstPicture, ( _src_x/_horizontalDecimation),
(_src_y/_verticalDecimation), 0, 0, 0, 0, _width, _height);
XSync(_x11Display, False);
@@ -170,93 +166,15 @@ Image<ColorRgb> & X11Grabber::grab()
_xImage = XGetImage(_x11Display, _pixmap, 0, 0, _width, _height, AllPlanes, ZPixmap);
}
}
else
else if (_XShmAvailable && !_useXGetImage)
{
if (_XShmAvailable && !_useXGetImage) {
XShmGetImage(_x11Display, _window, _xImage, _cropLeft, _cropTop, AllPlanes);
}
else
{
_xImage = XGetImage(_x11Display, _window, _cropLeft, _cropTop, _width, _height, AllPlanes, ZPixmap);
}
}
if (_xImage == nullptr)
{
Error(_log, "Grab Failed!");
return _image;
}
_imageResampler.processImage(reinterpret_cast<const uint8_t *>(_xImage->data), _xImage->width, _xImage->height, _xImage->bytes_per_line, PIXELFORMAT_BGR32, _image);
return _image;
}
int X11Grabber::grabFrame(Image<ColorRgb> & image)
{
if (_XRenderAvailable && !_useXGetImage)
{
double scale_x = static_cast<double>(_windowAttr.width / _horizontalDecimation) / static_cast<double>(_windowAttr.width);
double scale_y = static_cast<double>(_windowAttr.height / _verticalDecimation) / static_cast<double>(_windowAttr.height);
double scale = qMin(scale_y, scale_x);
_transform =
{
{
{
XDoubleToFixed(1),
XDoubleToFixed(0),
XDoubleToFixed(0)
},
{
XDoubleToFixed(0),
XDoubleToFixed(1),
XDoubleToFixed(0)
},
{
XDoubleToFixed(0),
XDoubleToFixed(0),
XDoubleToFixed(scale)
}
}
};
XRenderSetPictureTransform (_x11Display, _srcPicture, &_transform);
XRenderComposite( _x11Display, // dpy
PictOpSrc, // op
_srcPicture, // src
None, // mask
_dstPicture, // dst
_cropLeft / _horizontalDecimation, // src_x _cropLeft
_cropTop / _verticalDecimation, // src_y _cropTop
0, // mask_x
0, // mask_y
0, // dst_x
0, // dst_y
_width, // width
_height); // height
XSync(_x11Display, False);
if (_XShmAvailable)
{
XShmGetImage(_x11Display, _pixmap, _xImage, 0, 0, AllPlanes);
}
else
{
_xImage = XGetImage(_x11Display, _pixmap, 0, 0, _width, _height, AllPlanes, ZPixmap);
}
// use xshm
XShmGetImage(_x11Display, _window, _xImage, _src_x, _src_y, AllPlanes);
}
else
{
if (_XShmAvailable && !_useXGetImage) {
XShmGetImage(_x11Display, _window, _xImage, _cropLeft, _cropTop, AllPlanes);
}
else
{
_xImage = XGetImage(_x11Display, _window, _cropLeft, _cropTop, _width, _height, AllPlanes, ZPixmap);
}
// all things done by xgetimage
_xImage = XGetImage(_x11Display, _window, _src_x, _src_y, _width, _height, AllPlanes, ZPixmap);
}
if (_xImage == nullptr)
@@ -270,7 +188,7 @@ int X11Grabber::grabFrame(Image<ColorRgb> & image)
return 0;
}
int X11Grabber::updateScreenDimensions()
int X11Grabber::updateScreenDimensions(bool force)
{
const Status status = XGetWindowAttributes(_x11Display, _window, &_windowAttr);
if (status == 0)
@@ -279,7 +197,7 @@ int X11Grabber::updateScreenDimensions()
return -1;
}
if (_screenWidth == unsigned(_windowAttr.width) && _screenHeight == unsigned(_windowAttr.height))
if (!force && _screenWidth == unsigned(_windowAttr.width) && _screenHeight == unsigned(_windowAttr.height))
{
// No update required
return 0;
@@ -294,14 +212,16 @@ int X11Grabber::updateScreenDimensions()
_screenWidth = _windowAttr.width;
_screenHeight = _windowAttr.height;
int width=0, height=0;
// Image scaling is performed by XRender when available, otherwise by ImageResampler
if (_XRenderAvailable && !_useXGetImage)
{
_width = (_screenWidth > unsigned(_cropLeft + _cropRight))
width = (_screenWidth > unsigned(_cropLeft + _cropRight))
? ((_screenWidth - _cropLeft - _cropRight) / _horizontalDecimation)
: _screenWidth / _horizontalDecimation;
_height = (_screenHeight > unsigned(_cropTop + _cropBottom))
height = (_screenHeight > unsigned(_cropTop + _cropBottom))
? ((_screenHeight - _cropTop - _cropBottom) / _verticalDecimation)
: _screenHeight / _verticalDecimation;
@@ -309,19 +229,52 @@ int X11Grabber::updateScreenDimensions()
}
else
{
_width = (_screenWidth > unsigned(_cropLeft + _cropRight))
width = (_screenWidth > unsigned(_cropLeft + _cropRight))
? (_screenWidth - _cropLeft - _cropRight)
: _screenWidth;
_height = (_screenHeight > unsigned(_cropTop + _cropBottom))
height = (_screenHeight > unsigned(_cropTop + _cropBottom))
? (_screenHeight - _cropTop - _cropBottom)
: _screenHeight;
Info(_log, "Using XGetImage for grabbing");
}
// calculate final image dimensions and adjust top/left cropping in 3D modes
switch (_videoMode)
{
case VIDEO_3DSBS:
_width = width /2;
_height = height;
_src_x = _cropLeft / 2;
_src_y = _cropTop;
break;
case VIDEO_3DTAB:
_width = width;
_height = height / 2;
_src_x = _cropLeft;
_src_y = _cropTop / 2;
break;
case VIDEO_2D:
default:
_width = width;
_height = height;
_src_x = _cropLeft;
_src_y = _cropTop;
break;
}
Info(_log, "Update output image resolution: [%dx%d] to [%dx%d]", _image.width(), _image.height(), _width, _height);
_image.resize(_width, _height);
setupResources();
return 1;
}
void X11Grabber::setVideoMode(VideoMode mode)
{
Info(_log, "a %d", mode);
Grabber::setVideoMode(mode);
updateScreenDimensions(true);
}

View File

@@ -1,78 +1,24 @@
// Hyperion includes
#include <hyperion/Hyperion.h>
#include <hyperion/ImageProcessorFactory.h>
#include <hyperion/ImageProcessor.h>
// X11 grabber includes
#include <grabber/X11Wrapper.h>
#include <grabber/X11Grabber.h>
X11Wrapper::X11Wrapper(bool useXGetImage, int cropLeft, int cropRight, int cropTop, int cropBottom, int horizontalPixelDecimation, int verticalPixelDecimation, const unsigned updateRate_Hz, const int priority)
: GrabberWrapper("X11", priority)
, _updateInterval_ms(1000/updateRate_Hz)
, _timeout_ms(2 * _updateInterval_ms)
, _grabber(new X11Grabber(useXGetImage, cropLeft, cropRight, cropTop, cropBottom, horizontalPixelDecimation, verticalPixelDecimation))
, _ledColors(Hyperion::getInstance()->getLedCount(), ColorRgb{0,0,0})
: GrabberWrapper("X11", &_grabber, 0, 0, updateRate_Hz, priority, hyperion::COMP_GRABBER)
, _grabber(useXGetImage, cropLeft, cropRight, cropTop, cropBottom, horizontalPixelDecimation, verticalPixelDecimation)
, _init(false)
, _x11SetupSuccess(false)
{
// Configure the timer to generate events every n milliseconds
_timer.setInterval(_updateInterval_ms);
}
{}
X11Wrapper::~X11Wrapper()
{
delete _grabber;
}
bool X11Wrapper::start()
void X11Wrapper::action()
{
if (! _init )
{
_init = true;
_x11SetupSuccess = _grabber->Setup();
if ( _x11SetupSuccess )
if ( ! _grabber.Setup() )
{
_x11SetupSuccess = (_grabber->updateScreenDimensions() >= 0);
_processor->setSize(_grabber->getImageWidth(), _grabber->getImageHeight());
_image.resize(_grabber->getImageWidth(), _grabber->getImageHeight());
stop();
}
}
// Start the timer with the pre configured interval
if ( _x11SetupSuccess )
if (_grabber.updateScreenDimensions() >= 0 )
{
GrabberWrapper::start();
transferFrame(_grabber);
}
ErrorIf( ! _x11SetupSuccess, _log, "X11 Grabber start failed");
return _x11SetupSuccess;
}
void X11Wrapper::action()
{
int result = _grabber->updateScreenDimensions();
if (result < 0 )
{
return;
}
if ( result > 0 )
{
_processor->setSize(_grabber->getImageWidth(), _grabber->getImageHeight());
_image.resize(_grabber->getImageWidth(), _grabber->getImageHeight());
}
// Grab frame into the allocated image
_grabber->grabFrame(_image);
emit emitImage(_priority, _image, _timeout_ms);
_processor->process(_image, _ledColors);
setColors(_ledColors, _timeout_ms);
}
void X11Wrapper::setVideoMode(const VideoMode mode)
{
_grabber->setVideoMode(mode);
}