mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2025-03-01 10:33:28 +00:00
Added image flipping ability to MF Grabber
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
#include "MFSourceReaderCB.h"
|
||||
#include "grabber/MFGrabber.h"
|
||||
|
||||
MFGrabber::MFGrabber(const QString & device, unsigned width, unsigned height, unsigned fps, unsigned input, int pixelDecimation)
|
||||
// Constants
|
||||
namespace { const bool verbose = false; }
|
||||
|
||||
MFGrabber::MFGrabber(const QString & device, unsigned width, unsigned height, unsigned fps, unsigned input, int pixelDecimation, QString flipMode)
|
||||
: Grabber("V4L2:"+device)
|
||||
, _deviceName(device)
|
||||
, _hr(S_FALSE)
|
||||
@@ -30,6 +33,7 @@ MFGrabber::MFGrabber(const QString & device, unsigned width, unsigned height, un
|
||||
setInput(input);
|
||||
setWidthHeight(width, height);
|
||||
setFramerate(fps);
|
||||
setFlipMode(flipMode);
|
||||
// setDeviceVideoStandard(device, videoStandard); // TODO
|
||||
|
||||
CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
@@ -467,8 +471,8 @@ void MFGrabber::enumVideoCaptureDevices()
|
||||
if (pixelformat != PixelFormat::NO_CHANGE)
|
||||
{
|
||||
int framerate = fr1/fr2;
|
||||
QString sFrame = QString::number(framerate).rightJustified(2,' ');
|
||||
QString displayResolutions = QString::number(w).rightJustified(4,' ') +"x"+ QString::number(h).rightJustified(4,' ');
|
||||
QString sFrame = QString::number(framerate).rightJustified(2,' ').trimmed();
|
||||
QString displayResolutions = QString::number(w).rightJustified(4,' ').trimmed() +"x"+ QString::number(h).rightJustified(4,' ').trimmed();
|
||||
|
||||
if (!properties.displayResolutions.contains(displayResolutions))
|
||||
properties.displayResolutions << displayResolutions;
|
||||
@@ -486,7 +490,7 @@ void MFGrabber::enumVideoCaptureDevices()
|
||||
di.guid = format;
|
||||
properties.valid.append(di);
|
||||
|
||||
Debug(_log, "%s %d x %d @ %d fps (%s)", QSTRING_CSTR(dev), di.x, di.y, di.fps, QSTRING_CSTR(pixelFormatToString(di.pf)));
|
||||
DebugIf(verbose, _log, "%s %d x %d @ %d fps (%s)", QSTRING_CSTR(dev), di.x, di.y, di.fps, QSTRING_CSTR(pixelFormatToString(di.pf)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,12 +557,12 @@ void MFGrabber::process_image(const void *frameImageBuffer, int size)
|
||||
|
||||
for (unsigned int i=0; i < _threadManager._maxThreads && _threadManager._threads != nullptr; i++)
|
||||
{
|
||||
MFThread* _thread=_threadManager._threads[i];
|
||||
MFThread* _thread = _threadManager._threads[i];
|
||||
connect(_thread, SIGNAL(newFrame(unsigned int, const Image<ColorRgb> &,unsigned int)), this , SLOT(newThreadFrame(unsigned int, const Image<ColorRgb> &, unsigned int)));
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int i=0;_threadManager.isActive() && i < _threadManager._maxThreads && _threadManager._threads != nullptr; i++)
|
||||
for (unsigned int i = 0;_threadManager.isActive() && i < _threadManager._maxThreads && _threadManager._threads != nullptr; i++)
|
||||
{
|
||||
if ((_threadManager._threads[i]->isFinished() || !_threadManager._threads[i]->isRunning()))
|
||||
{
|
||||
@@ -566,11 +570,8 @@ void MFGrabber::process_image(const void *frameImageBuffer, int size)
|
||||
if ( _threadManager._threads[i]->isBusy() == false)
|
||||
{
|
||||
MFThread* _thread = _threadManager._threads[i];
|
||||
_thread->setup(i, _pixelFormat, (uint8_t *)frameImageBuffer, size, _width, _height, _lineLength, _subsamp, _cropLeft, _cropTop, _cropBottom, _cropRight, _videoMode, processFrameIndex, _pixelDecimation);
|
||||
|
||||
if (_threadManager._maxThreads > 1)
|
||||
_threadManager._threads[i]->start();
|
||||
|
||||
_thread->setup(i, _pixelFormat, (uint8_t *)frameImageBuffer, size, _width, _height, _lineLength, _subsamp, _cropLeft, _cropTop, _cropBottom, _cropRight, _videoMode, _flipMode, processFrameIndex, _pixelDecimation);
|
||||
_threadManager._threads[i]->start();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -586,7 +587,8 @@ void MFGrabber::setSignalThreshold(double redSignalThreshold, double greenSignal
|
||||
_noSignalThresholdColor.blue = uint8_t(255*blueSignalThreshold);
|
||||
_noSignalCounterThreshold = qMax(1, noSignalCounterThreshold);
|
||||
|
||||
Info(_log, "Signal threshold set to: {%d, %d, %d} and frames: %d", _noSignalThresholdColor.red, _noSignalThresholdColor.green, _noSignalThresholdColor.blue, _noSignalCounterThreshold );
|
||||
if(_signalDetectionEnabled)
|
||||
Info(_log, "Signal threshold set to: {%d, %d, %d} and frames: %d", _noSignalThresholdColor.red, _noSignalThresholdColor.green, _noSignalThresholdColor.blue, _noSignalCounterThreshold );
|
||||
}
|
||||
|
||||
void MFGrabber::setSignalDetectionOffset(double horizontalMin, double verticalMin, double horizontalMax, double verticalMax)
|
||||
@@ -599,7 +601,8 @@ void MFGrabber::setSignalDetectionOffset(double horizontalMin, double verticalMi
|
||||
_x_frac_max = horizontalMax;
|
||||
_y_frac_max = verticalMax;
|
||||
|
||||
Info(_log, "Signal detection area set to: %f,%f x %f,%f", _x_frac_min, _y_frac_min, _x_frac_max, _y_frac_max );
|
||||
if(_signalDetectionEnabled)
|
||||
Info(_log, "Signal detection area set to: %f,%f x %f,%f", _x_frac_min, _y_frac_min, _x_frac_max, _y_frac_max );
|
||||
}
|
||||
|
||||
bool MFGrabber::start()
|
||||
@@ -744,6 +747,12 @@ void MFGrabber::setPixelDecimation(int pixelDecimation)
|
||||
_pixelDecimation = pixelDecimation;
|
||||
}
|
||||
|
||||
void MFGrabber::setFlipMode(QString flipMode)
|
||||
{
|
||||
if(_flipMode != parseFlipMode(flipMode))
|
||||
Grabber::setFlipMode(parseFlipMode(flipMode));
|
||||
}
|
||||
|
||||
void MFGrabber::setDeviceVideoStandard(QString device, VideoStandard videoStandard)
|
||||
{
|
||||
if(_deviceName != device)
|
||||
|
@@ -3,26 +3,31 @@
|
||||
volatile bool MFThread::_isActive = false;
|
||||
|
||||
MFThread::MFThread()
|
||||
: _localData(nullptr)
|
||||
: _isBusy(false)
|
||||
, _semaphore(1)
|
||||
, _localData(nullptr)
|
||||
, _localDataSize(0)
|
||||
, _decompress(nullptr)
|
||||
, _scalingFactorsCount(0)
|
||||
, _scalingFactors(nullptr)
|
||||
, _isBusy(false)
|
||||
, _semaphore(1)
|
||||
, _transform(nullptr)
|
||||
, _decompress(nullptr)
|
||||
, _xform(nullptr)
|
||||
, _imageResampler()
|
||||
{
|
||||
}
|
||||
|
||||
MFThread::~MFThread()
|
||||
{
|
||||
if (_decompress == nullptr)
|
||||
if (_transform)
|
||||
tjDestroy(_transform);
|
||||
|
||||
if (_decompress)
|
||||
tjDestroy(_decompress);
|
||||
|
||||
if (_localData != NULL)
|
||||
if (_localData)
|
||||
{
|
||||
free(_localData);
|
||||
_localData = NULL;
|
||||
_localData = nullptr;
|
||||
_localDataSize = 0;
|
||||
}
|
||||
}
|
||||
@@ -31,9 +36,9 @@ void MFThread::setup(
|
||||
unsigned int threadIndex, PixelFormat pixelFormat, uint8_t* sharedData,
|
||||
int size, int width, int height, int lineLength,
|
||||
int subsamp, unsigned cropLeft, unsigned cropTop, unsigned cropBottom, unsigned cropRight,
|
||||
VideoMode videoMode, int currentFrame, int pixelDecimation)
|
||||
VideoMode videoMode, FlipMode flipMode, int currentFrame, int pixelDecimation)
|
||||
{
|
||||
_workerIndex = threadIndex;
|
||||
_threadIndex = threadIndex;
|
||||
_lineLength = lineLength;
|
||||
_pixelFormat = pixelFormat;
|
||||
_size = size;
|
||||
@@ -44,26 +49,25 @@ void MFThread::setup(
|
||||
_cropTop = cropTop;
|
||||
_cropBottom = cropBottom;
|
||||
_cropRight = cropRight;
|
||||
_flipMode = flipMode;
|
||||
_currentFrame = currentFrame;
|
||||
_pixelDecimation = pixelDecimation;
|
||||
|
||||
_imageResampler.setVideoMode(videoMode);
|
||||
_imageResampler.setFlipMode(_flipMode);
|
||||
_imageResampler.setCropping(cropLeft, cropRight, cropTop, cropBottom);
|
||||
_imageResampler.setHorizontalPixelDecimation(_pixelDecimation);
|
||||
_imageResampler.setVerticalPixelDecimation(_pixelDecimation);
|
||||
_imageResampler.setFlipMode(FlipMode::NO_CHANGE);
|
||||
|
||||
if (size > _localDataSize)
|
||||
{
|
||||
if (_localData != NULL)
|
||||
{
|
||||
free(_localData);
|
||||
_localData = NULL;
|
||||
_localDataSize = 0;
|
||||
}
|
||||
_localData = (uint8_t *) malloc(size+1);
|
||||
if (_localData)
|
||||
tjFree(_localData);
|
||||
|
||||
_localData = (uint8_t*)tjAlloc(size + 1);
|
||||
_localDataSize = size;
|
||||
}
|
||||
|
||||
memcpy(_localData, sharedData, size);
|
||||
}
|
||||
|
||||
@@ -79,7 +83,7 @@ void MFThread::run()
|
||||
{
|
||||
Image<ColorRgb> image = Image<ColorRgb>();
|
||||
_imageResampler.processImage(_localData, _width, _height, _lineLength, PixelFormat::BGR24, image);
|
||||
emit newFrame(_workerIndex, image, _currentFrame);
|
||||
emit newFrame(_threadIndex, image, _currentFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,11 +112,36 @@ void MFThread::noBusy()
|
||||
|
||||
void MFThread::processImageMjpeg()
|
||||
{
|
||||
if (_decompress == nullptr)
|
||||
if (!_transform && _flipMode != FlipMode::NO_CHANGE)
|
||||
{
|
||||
_transform = tjInitTransform();
|
||||
_xform = new tjtransform();
|
||||
}
|
||||
|
||||
if (_flipMode == FlipMode::BOTH || _flipMode == FlipMode::HORIZONTAL)
|
||||
{
|
||||
_xform->op = TJXOP_HFLIP;
|
||||
uint8_t* dstBuf = nullptr;
|
||||
unsigned long dstSize = 0;
|
||||
tjTransform(_transform, _localData, _size, 1, &dstBuf, &dstSize, _xform, TJFLAG_FASTDCT | TJFLAG_FASTUPSAMPLE);
|
||||
_localData = dstBuf;
|
||||
_size = dstSize;
|
||||
}
|
||||
|
||||
if (_flipMode == FlipMode::BOTH || _flipMode == FlipMode::VERTICAL)
|
||||
{
|
||||
_xform->op = TJXOP_VFLIP;
|
||||
uint8_t *dstBuf = nullptr;
|
||||
unsigned long dstSize = 0;
|
||||
tjTransform(_transform, _localData, _size, 1, &dstBuf, &dstSize, _xform, TJFLAG_FASTDCT | TJFLAG_FASTUPSAMPLE);
|
||||
_localData = dstBuf;
|
||||
_size = dstSize;
|
||||
}
|
||||
|
||||
if (!_decompress)
|
||||
{
|
||||
_decompress = tjInitDecompress();
|
||||
_scalingFactors = tjGetScalingFactors (&_scalingFactorsCount);
|
||||
tjhandle handle=NULL;
|
||||
_scalingFactors = tjGetScalingFactors(&_scalingFactorsCount);
|
||||
}
|
||||
|
||||
if (tjDecompressHeader2(_decompress, _localData, _size, &_width, &_height, &_subsamp) != 0)
|
||||
@@ -153,10 +182,10 @@ void MFThread::processImageMjpeg()
|
||||
|
||||
// got image, process it
|
||||
if ( !(_cropLeft > 0 || _cropTop > 0 || _cropBottom > 0 || _cropRight > 0))
|
||||
emit newFrame(_workerIndex, srcImage, _currentFrame);
|
||||
emit newFrame(_threadIndex, srcImage, _currentFrame);
|
||||
else
|
||||
{
|
||||
// calculate the output size
|
||||
// calculate the output size
|
||||
int outputWidth = (_width - _cropLeft - _cropRight);
|
||||
int outputHeight = (_height - _cropTop - _cropBottom);
|
||||
|
||||
@@ -171,10 +200,12 @@ void MFThread::processImageMjpeg()
|
||||
unsigned char* dest = (unsigned char*)destImage.memptr() + y*destImage.width()*3;
|
||||
memcpy(dest, source, destImage.width()*3);
|
||||
free(source);
|
||||
source = nullptr;
|
||||
free(dest);
|
||||
dest = nullptr;
|
||||
}
|
||||
|
||||
// emit
|
||||
emit newFrame(_workerIndex, destImage, _currentFrame);
|
||||
emit newFrame(_threadIndex, destImage, _currentFrame);
|
||||
}
|
||||
}
|
||||
|
@@ -5,9 +5,9 @@
|
||||
// qt
|
||||
#include <QTimer>
|
||||
|
||||
MFWrapper::MFWrapper(const QString &device, unsigned grabWidth, unsigned grabHeight, unsigned fps, unsigned input, int pixelDecimation )
|
||||
MFWrapper::MFWrapper(const QString &device, unsigned grabWidth, unsigned grabHeight, unsigned fps, unsigned input, int pixelDecimation, QString flipMode)
|
||||
: GrabberWrapper("V4L2:"+device, &_grabber, grabWidth, grabHeight, 10)
|
||||
, _grabber(device, grabWidth, grabHeight, fps, input, pixelDecimation)
|
||||
, _grabber(device, grabWidth, grabHeight, fps, input, pixelDecimation, flipMode)
|
||||
{
|
||||
_ggrabber = &_grabber;
|
||||
|
||||
@@ -123,6 +123,9 @@ void MFWrapper::handleSettingsUpdate(settings::type type, const QJsonDocument& c
|
||||
// image size decimation
|
||||
_grabber.setPixelDecimation(obj["sizeDecimation"].toInt(8));
|
||||
|
||||
// flip mode
|
||||
_grabber.setFlipMode(obj["flip"].toString("no-change"));
|
||||
|
||||
// image cropping
|
||||
_grabber.setCropping(
|
||||
obj["cropLeft"].toInt(0),
|
||||
|
@@ -12,8 +12,8 @@ QtGrabber::QtGrabber(int cropLeft, int cropRight, int cropTop, int cropBottom, i
|
||||
: Grabber("QTGRABBER", 0, 0, cropLeft, cropRight, cropTop, cropBottom)
|
||||
, _display(unsigned(display))
|
||||
, _pixelDecimation(pixelDecimation)
|
||||
, _screenWidth(0)
|
||||
, _screenHeight(0)
|
||||
, _calculatedWidth(0)
|
||||
, _calculatedHeight(0)
|
||||
, _src_x(0)
|
||||
, _src_y(0)
|
||||
, _src_x_max(0)
|
||||
@@ -98,20 +98,13 @@ int QtGrabber::grabFrame(Image<ColorRgb> & image)
|
||||
setEnabled(setupDisplay());
|
||||
return -1;
|
||||
}
|
||||
QPixmap originalPixmap = _screen->grabWindow(0, _src_x, _src_y, _src_x_max, _src_y_max);
|
||||
QPixmap resizedPixmap = originalPixmap.scaled(_width,_height);
|
||||
QImage imageFrame = resizedPixmap.toImage().convertToFormat( QImage::Format_RGB888);
|
||||
image.resize(imageFrame.width(), imageFrame.height());
|
||||
|
||||
for (int y=0; y<imageFrame.height(); ++y)
|
||||
for (int x=0; x<imageFrame.width(); ++x)
|
||||
{
|
||||
QColor inPixel(imageFrame.pixel(x,y));
|
||||
ColorRgb & outPixel = image(x,y);
|
||||
outPixel.red = inPixel.red();
|
||||
outPixel.green = inPixel.green();
|
||||
outPixel.blue = inPixel.blue();
|
||||
}
|
||||
QPixmap originalPixmap = _screen->grabWindow(0, _src_x, _src_y, _src_x_max, _src_y_max);
|
||||
QImage imageFrame = originalPixmap.toImage().scaled(_calculatedWidth, _calculatedHeight).convertToFormat( QImage::Format_RGB888);
|
||||
image.resize(_calculatedWidth, _calculatedHeight);
|
||||
|
||||
for (int y = 0; y < imageFrame.height(); y++)
|
||||
memcpy((unsigned char*)image.memptr() + y * image.width() * 3, (unsigned char*)imageFrame.scanLine(y), imageFrame.width() * 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -122,59 +115,59 @@ int QtGrabber::updateScreenDimensions(bool force)
|
||||
return -1;
|
||||
|
||||
const QRect& geo = _screen->geometry();
|
||||
if (!force && _screenWidth == unsigned(geo.right()) && _screenHeight == unsigned(geo.bottom()))
|
||||
if (!force && _width == unsigned(geo.right()) && _height == unsigned(geo.bottom()))
|
||||
{
|
||||
// No update required
|
||||
return 0;
|
||||
}
|
||||
|
||||
Info(_log, "Update of screen resolution: [%dx%d] to [%dx%d]", _screenWidth, _screenHeight, geo.right(), geo.bottom());
|
||||
_screenWidth = geo.right() - geo.left();
|
||||
_screenHeight = geo.bottom() - geo.top();
|
||||
Info(_log, "Update of screen resolution: [%dx%d] to [%dx%d]", _width, _height, geo.right(), geo.bottom());
|
||||
_width = geo.right() - geo.left();
|
||||
_height = geo.bottom() - geo.top();
|
||||
|
||||
int width=0, height=0;
|
||||
|
||||
// Image scaling is performed by Qt
|
||||
width = (_screenWidth > unsigned(_cropLeft + _cropRight))
|
||||
? ((_screenWidth - _cropLeft - _cropRight) / _pixelDecimation)
|
||||
: (_screenWidth / _pixelDecimation);
|
||||
width = (_width > (_cropLeft + _cropRight))
|
||||
? ((_width - _cropLeft - _cropRight) / _pixelDecimation)
|
||||
: (_width / _pixelDecimation);
|
||||
|
||||
height = (_screenHeight > unsigned(_cropTop + _cropBottom))
|
||||
? ((_screenHeight - _cropTop - _cropBottom) / _pixelDecimation)
|
||||
: (_screenHeight / _pixelDecimation);
|
||||
height = (_height > (_cropTop + _cropBottom))
|
||||
? ((_height - _cropTop - _cropBottom) / _pixelDecimation)
|
||||
: (_height / _pixelDecimation);
|
||||
|
||||
|
||||
// calculate final image dimensions and adjust top/left cropping in 3D modes
|
||||
switch (_videoMode)
|
||||
{
|
||||
case VideoMode::VIDEO_3DSBS:
|
||||
_width = width /2;
|
||||
_height = height;
|
||||
_calculatedWidth = width /2;
|
||||
_calculatedHeight = height;
|
||||
_src_x = _cropLeft / 2;
|
||||
_src_y = _cropTop;
|
||||
_src_x_max = (_screenWidth / 2) - _cropRight;
|
||||
_src_y_max = _screenHeight - _cropBottom;
|
||||
_src_x_max = (_width / 2) - _cropRight - _cropLeft;
|
||||
_src_y_max = _height - _cropBottom - _cropTop;
|
||||
break;
|
||||
case VideoMode::VIDEO_3DTAB:
|
||||
_width = width;
|
||||
_height = height / 2;
|
||||
_calculatedWidth = width;
|
||||
_calculatedHeight = height / 2;
|
||||
_src_x = _cropLeft;
|
||||
_src_y = _cropTop / 2;
|
||||
_src_x_max = _screenWidth - _cropRight;
|
||||
_src_y_max = (_screenHeight / 2) - _cropBottom;
|
||||
_src_x_max = _width - _cropRight - _cropLeft;
|
||||
_src_y_max = (_height / 2) - _cropBottom - _cropTop;
|
||||
break;
|
||||
case VideoMode::VIDEO_2D:
|
||||
default:
|
||||
_width = width;
|
||||
_height = height;
|
||||
_calculatedWidth = width;
|
||||
_calculatedHeight = height;
|
||||
_src_x = _cropLeft;
|
||||
_src_y = _cropTop;
|
||||
_src_x_max = _screenWidth - _cropRight;
|
||||
_src_y_max = _screenHeight - _cropBottom;
|
||||
_src_x_max = _width - _cropRight - _cropLeft;
|
||||
_src_y_max = _height - _cropBottom - _cropTop;
|
||||
break;
|
||||
}
|
||||
|
||||
Info(_log, "Update output image resolution to [%dx%d]", _width, _height);
|
||||
Info(_log, "Update output image resolution to [%dx%d]", _calculatedWidth, _calculatedHeight);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user