Added image flipping ability to MF Grabber

This commit is contained in:
Paulchen Panther 2021-01-24 12:16:16 +01:00
parent d5717af2df
commit 4254f36bba
18 changed files with 255 additions and 164 deletions

2
.vscode/launch.json vendored
View File

@ -32,7 +32,7 @@
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false
"console": "internalConsole"
}
]
}

View File

@ -258,6 +258,9 @@
"edt_conf_enum_NTSC": "NTSC",
"edt_conf_enum_PAL": "PAL",
"edt_conf_enum_SECAM": "SECAM",
"edt_conf_enum_HORIZONTAL": "Horizontal",
"edt_conf_enum_VERTICAL": "Vertikal",
"edt_conf_enum_BOTH": "Horizontal & Vertikal",
"edt_conf_enum_automatic": "Automatisch",
"edt_conf_enum_bbclassic": "Klassisch",
"edt_conf_enum_bbdefault": "Standard",
@ -424,6 +427,8 @@
"edt_conf_v4l2_sizeDecimation_title": "Bildverkleinerung Faktor",
"edt_conf_v4l2_standard_expl": "Wähle das passende Videoformat deiner Region. Auf 'Automatisch' wird der gewählte Modus vom v4l interface beibehalten.",
"edt_conf_v4l2_standard_title": "Videoformat",
"edt_conf_v4l2_flip_expl": "Hiermit kannst du das Bild in horizontaler, vertikaler oder beiden Richtung spiegeln.",
"edt_conf_v4l2_flip_title": "Spiegelung",
"edt_conf_webc_crtPath_expl": "Pfad zur Zertifikats-Datei (Format sollte PEM sein)",
"edt_conf_webc_crtPath_title": "Zertifikats-Pfad",
"edt_conf_webc_docroot_expl": "Lokaler Pfad zum WebUI Wurzelverzeichnis (Nur für WebUI Entwickler)",

View File

@ -258,6 +258,9 @@
"edt_conf_enum_NTSC": "NTSC",
"edt_conf_enum_PAL": "PAL",
"edt_conf_enum_SECAM": "SECAM",
"edt_conf_enum_HORIZONTAL": "Horizontal",
"edt_conf_enum_VERTICAL": "Vertical",
"edt_conf_enum_BOTH": "Horizontal & Vertical",
"edt_conf_enum_automatic": "Automatic",
"edt_conf_enum_bbclassic": "Classic",
"edt_conf_enum_bbdefault": "Default",
@ -424,6 +427,8 @@
"edt_conf_v4l2_sizeDecimation_title": "Size decimation",
"edt_conf_v4l2_standard_expl": "Select the video standard for your region. 'Automatic' keeps the value chosen by the v4l2 interface.",
"edt_conf_v4l2_standard_title": "Video standard",
"edt_conf_v4l2_flip_expl": "This allows you to flip the image horizontally, vertically, or both.",
"edt_conf_v4l2_flip_title": "Image flip",
"edt_conf_v4l2_fpsSoftwareDecimation_title" : "Software frame skipping",
"edt_conf_v4l2_fpsSoftwareDecimation_expl" : "To save resources every n'th frame will be processed only. For ex. if grabber is set to 30FPS with this option set to 5 the final result will be around 6FPS (1 - disabled)",
"edt_conf_v4l2_encoding_title" : "Encoding format",

View File

@ -13,35 +13,40 @@ $(document).ready(function () {
"type": "string",
"title": "edt_conf_v4l2_device_title",
"propertyOrder": 1,
"required": true
"required": true,
"custom": true
},
"device_inputs":
{
"type": "string",
"title": "edt_conf_v4l2_input_title",
"propertyOrder": 3,
"required": true
"required": true,
"custom": false
},
"encoding_format":
{
"type": "string",
"title": "edt_conf_v4l2_encoding_title",
"propertyOrder": 5,
"required": true
"required": true,
"custom": false
},
"resolutions":
{
"type": "string",
"title": "edt_conf_v4l2_resolution_title",
"propertyOrder": 8,
"required": true
"propertyOrder": 9,
"required": true,
"custom": true
},
"framerates":
{
"type": "string",
"title": "edt_conf_v4l2_framerate_title",
"propertyOrder": 11,
"required": true
"propertyOrder": 12,
"required": true,
"custom": true
}
};
@ -52,7 +57,7 @@ $(document).ready(function () {
var enumTitelVals = [];
var v4l2_properties = JSON.parse(JSON.stringify(window.serverInfo.grabbers.v4l2_properties));
if (key === 'available_devices') {
if (key == 'available_devices') {
for (var i = 0; i < v4l2_properties.length; i++) {
enumVals.push(v4l2_properties[i]['device']);
@ -79,10 +84,12 @@ $(document).ready(function () {
}
}
if (key != 'device_inputs' || enumVals.length > 0) {
window.schema.grabberV4L2.properties[key] = {
"type": schema[key].type,
"title": schema[key].title,
"enum": [].concat(["auto"], enumVals, ["custom"]),
...(schema[key].custom ? {"enum": [].concat(["auto"], enumVals, ["custom"]),} : {"enum": [].concat(["auto"], enumVals),}),
// "enum": [].concat(["auto"], enumVals, ["custom"]),
"options":
{
"enum_titles": [].concat(["edt_conf_enum_automatic"], enumTitelVals, ["edt_conf_enum_custom"]),
@ -91,6 +98,7 @@ $(document).ready(function () {
"required": schema[key].required
};
}
}
};
// Switch between visible states

View File

@ -69,6 +69,7 @@
"height" : 0,
"fps" : 15,
"standard" : "NO_CHANGE",
"flip" : "NO_CHANGE",
"fpsSoftwareDecimation" : 1,
"sizeDecimation" : 8,
"cropLeft" : 0,

View File

@ -56,7 +56,7 @@ public:
QList<DevicePropertiesItem> valid = QList<DevicePropertiesItem>();
};
MFGrabber(const QString & device, const unsigned width, const unsigned height, const unsigned fps, const unsigned input, int pixelDecimation);
MFGrabber(const QString & device, const unsigned width, const unsigned height, const unsigned fps, const unsigned input, int pixelDecimation, QString flipMode);
~MFGrabber() override;
void receive_image(const void *frameImageBuffer, int size);
@ -80,6 +80,7 @@ public:
bool setFramerate(int fps) override;
void setFpsSoftwareDecimation(int decimation);
void setEncoding(QString enc);
void setFlipMode(QString flipMode);
void setBrightnessContrastSaturationHue(int brightness, int contrast, int saturation, int hue);
public slots:

View File

@ -32,7 +32,7 @@ public:
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);
void run();
bool isBusy();
@ -45,29 +45,32 @@ private:
void processImageMjpeg();
#ifdef HAVE_TURBO_JPEG
tjhandle _decompress;
tjhandle _transform,
_decompress;
tjscalingfactor* _scalingFactors;
tjtransform* _xform;
#endif
static volatile bool _isActive;
volatile bool _isBusy;
QSemaphore _semaphore;
unsigned int _workerIndex;
unsigned int _threadIndex;
PixelFormat _pixelFormat;
uint8_t* _localData;
int _localDataSize;
int _scalingFactorsCount;
int _size;
int _width;
int _height;
int _lineLength;
int _subsamp;
unsigned _cropLeft;
unsigned _cropTop;
unsigned _cropBottom;
unsigned _cropRight;
int _currentFrame;
int _pixelDecimation;
int _localDataSize,
_scalingFactorsCount,
_size,
_width,
_height,
_lineLength,
_subsamp,
_currentFrame,
_pixelDecimation;
unsigned _cropLeft,
_cropTop,
_cropBottom,
_cropRight;
FlipMode _flipMode;
ImageResampler _imageResampler;
};

View File

@ -8,7 +8,7 @@ class MFWrapper : public GrabberWrapper
Q_OBJECT
public:
MFWrapper(const QString & device, const unsigned grabWidth, const unsigned grabHeight, const unsigned fps, const unsigned input, int pixelDecimation);
MFWrapper(const QString & device, const unsigned grabWidth, const unsigned grabHeight, const unsigned fps, const unsigned input, int pixelDecimation, QString flipMode);
~MFWrapper() override;
bool getSignalDetectionEnable() const;

View File

@ -86,8 +86,8 @@ private:
unsigned _display;
int _pixelDecimation;
unsigned _screenWidth;
unsigned _screenHeight;
unsigned _calculatedWidth;
unsigned _calculatedHeight;
unsigned _src_x;
unsigned _src_y;
unsigned _src_x_max;

View File

@ -30,6 +30,12 @@ public:
///
virtual void setVideoMode(VideoMode mode);
///
/// Apply new flip mode (vertical/horizontal/both)
/// @param[in] mode The new flip mode
///
virtual void setFlipMode(FlipMode mode);
///
/// @brief Apply new crop values, on errors reject the values
///
@ -161,9 +167,12 @@ protected:
bool _useImageResampler;
/// the selected VideoMode
/// The selected VideoMode
VideoMode _videoMode;
/// The used Flip Mode
FlipMode _flipMode;
/// With of the captured snapshot [pixels]
int _width;

View File

@ -120,10 +120,10 @@ inline QString pixelFormatToString(const PixelFormat& pixelFormat)
enum class FlipMode
{
HORIZONTAL = 1,
VERTICAL = 2,
BOTH = HORIZONTAL | VERTICAL,
NO_CHANGE = 4
HORIZONTAL,
VERTICAL,
BOTH,
NO_CHANGE
};
inline FlipMode parseFlipMode(const QString& flipMode)
@ -131,15 +131,15 @@ inline FlipMode parseFlipMode(const QString& flipMode)
// convert to lower case
QString mode = flipMode.toLower();
if (flipMode.compare("horizontal") == 0)
if (mode.compare("horizontal") == 0)
{
return FlipMode::HORIZONTAL;
}
else if (flipMode.compare("vertical") == 0)
else if (mode.compare("vertical") == 0)
{
return FlipMode::VERTICAL;
}
else if (flipMode.compare("both") == 0)
else if (mode.compare("both") == 0)
{
return FlipMode::BOTH;
}
@ -150,7 +150,6 @@ inline FlipMode parseFlipMode(const QString& flipMode)
inline QString flipModeToString(const FlipMode& flipMode)
{
if ( flipMode == FlipMode::HORIZONTAL)
{
return "horizontal";

View File

@ -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)));
}
}
@ -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)
_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,6 +587,7 @@ void MFGrabber::setSignalThreshold(double redSignalThreshold, double greenSignal
_noSignalThresholdColor.blue = uint8_t(255*blueSignalThreshold);
_noSignalCounterThreshold = qMax(1, noSignalCounterThreshold);
if(_signalDetectionEnabled)
Info(_log, "Signal threshold set to: {%d, %d, %d} and frames: %d", _noSignalThresholdColor.red, _noSignalThresholdColor.green, _noSignalThresholdColor.blue, _noSignalCounterThreshold );
}
@ -599,6 +601,7 @@ void MFGrabber::setSignalDetectionOffset(double horizontalMin, double verticalMi
_x_frac_max = horizontalMax;
_y_frac_max = verticalMax;
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 );
}
@ -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)

View File

@ -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;
}
if (tjDecompressHeader2(_decompress, _localData, _size, &_width, &_height, &_subsamp) != 0)
@ -153,7 +182,7 @@ 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
@ -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);
}
}

View File

@ -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),

View File

@ -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;
}

View File

@ -4,6 +4,7 @@ Grabber::Grabber(const QString& grabberName, int width, int height, int cropLeft
: _imageResampler()
, _useImageResampler(true)
, _videoMode(VideoMode::VIDEO_2D)
, _flipMode(FlipMode::NO_CHANGE)
, _width(width)
, _height(height)
, _fps(15)
@ -35,6 +36,16 @@ void Grabber::setVideoMode(VideoMode mode)
}
}
void Grabber::setFlipMode(FlipMode mode)
{
Debug(_log,"Set flipmode to %d", mode);
_flipMode = mode;
if ( _useImageResampler )
{
_imageResampler.setFlipMode(_flipMode);
}
}
void Grabber::setCropping(unsigned cropLeft, unsigned cropRight, unsigned cropTop, unsigned cropBottom)
{
if (_width>0 && _height>0)

View File

@ -52,6 +52,18 @@
"required" : true,
"propertyOrder" : 7
},
"flip" :
{
"type" : "string",
"title" : "edt_conf_v4l2_flip_title",
"enum" : ["NO_CHANGE", "HORIZONTAL","VERTICAL","BOTH"],
"default" : "NO_CHANGE",
"options" : {
"enum_titles" : ["edt_conf_enum_NO_CHANGE", "edt_conf_enum_HORIZONTAL", "edt_conf_enum_VERTICAL", "edt_conf_enum_BOTH"]
},
"required" : true,
"propertyOrder" : 8
},
"width" :
{
"type" : "integer",
@ -63,8 +75,8 @@
"hidden":true
},
"required" : true,
"propertyOrder" : 9,
"comment" : "The 'resolutions' settings are dynamically inserted into the WebUI under PropertyOrder '8'."
"propertyOrder" : 10,
"comment" : "The 'resolutions' settings are dynamically inserted into the WebUI under PropertyOrder '9'."
},
"height" :
{
@ -77,8 +89,8 @@
"hidden":true
},
"required" : true,
"propertyOrder" : 10,
"comment" : "The 'resolutions' settings are dynamically inserted into the WebUI under PropertyOrder '6'."
"propertyOrder" : 11,
"comment" : "The 'resolutions' settings are dynamically inserted into the WebUI under PropertyOrder '9'."
},
"fps" :
{
@ -91,8 +103,8 @@
"hidden":true
},
"required" : true,
"propertyOrder" : 12,
"comment" : "The 'framerates' setting is dynamically inserted into the WebUI under PropertyOrder '11'."
"propertyOrder" : 13,
"comment" : "The 'framerates' setting is dynamically inserted into the WebUI under PropertyOrder '12'."
},
"fpsSoftwareDecimation" :
{
@ -102,7 +114,7 @@
"maximum" : 60,
"default" : 1,
"required" : true,
"propertyOrder" : 13
"propertyOrder" : 14
},
"sizeDecimation" :
{
@ -112,7 +124,7 @@
"maximum" : 30,
"default" : 6,
"required" : true,
"propertyOrder" : 14
"propertyOrder" : 15
},
"cropLeft" :
{
@ -122,7 +134,7 @@
"default" : 0,
"append" : "edt_append_pixel",
"required" : true,
"propertyOrder" : 15
"propertyOrder" : 16
},
"cropRight" :
{
@ -132,7 +144,7 @@
"default" : 0,
"append" : "edt_append_pixel",
"required" : true,
"propertyOrder" : 16
"propertyOrder" : 17
},
"cropTop" :
{
@ -142,7 +154,7 @@
"default" : 0,
"append" : "edt_append_pixel",
"required" : true,
"propertyOrder" : 17
"propertyOrder" : 18
},
"cropBottom" :
{
@ -152,7 +164,7 @@
"default" : 0,
"append" : "edt_append_pixel",
"required" : true,
"propertyOrder" : 18
"propertyOrder" : 19
},
"cecDetection" :
{
@ -160,7 +172,7 @@
"title" : "edt_conf_v4l2_cecDetection_title",
"default" : false,
"required" : true,
"propertyOrder" : 19
"propertyOrder" : 20
},
"signalDetection" :
{
@ -168,7 +180,7 @@
"title" : "edt_conf_v4l2_signalDetection_title",
"default" : false,
"required" : true,
"propertyOrder" : 20
"propertyOrder" : 21
},
"redSignalThreshold" :
{
@ -184,7 +196,7 @@
}
},
"required" : true,
"propertyOrder" : 21
"propertyOrder" : 22
},
"greenSignalThreshold" :
{
@ -200,7 +212,7 @@
}
},
"required" : true,
"propertyOrder" : 22
"propertyOrder" : 23
},
"blueSignalThreshold" :
{
@ -216,7 +228,7 @@
}
},
"required" : true,
"propertyOrder" : 23
"propertyOrder" : 24
},
"noSignalCounterThreshold" :
{
@ -231,7 +243,7 @@
}
},
"required" : true,
"propertyOrder" : 24
"propertyOrder" : 25
},
"sDVOffsetMin" :
{
@ -247,7 +259,7 @@
}
},
"required" : true,
"propertyOrder" : 25
"propertyOrder" : 26
},
"sDVOffsetMax" :
{
@ -263,7 +275,7 @@
}
},
"required" : true,
"propertyOrder" : 26
"propertyOrder" : 27
},
"sDHOffsetMin" :
{
@ -279,7 +291,7 @@
}
},
"required" : true,
"propertyOrder" : 27
"propertyOrder" : 28
},
"sDHOffsetMax" :
{
@ -295,7 +307,7 @@
}
},
"required" : true,
"propertyOrder" : 28
"propertyOrder" : 29
},
"hardware_brightness" :
{
@ -303,7 +315,7 @@
"title" : "edt_conf_v4l2_hardware_brightness_title",
"default" : 0,
"required" : true,
"propertyOrder" : 29
"propertyOrder" : 30
},
"hardware_contrast" :
{
@ -311,7 +323,7 @@
"title" : "edt_conf_v4l2_hardware_contrast_title",
"default" : 0,
"required" : true,
"propertyOrder" : 30
"propertyOrder" : 31
},
"hardware_saturation" :
{
@ -319,7 +331,7 @@
"title" : "edt_conf_v4l2_hardware_saturation_title",
"default" : 0,
"required" : true,
"propertyOrder" : 31
"propertyOrder" : 32
},
"hardware_hue" :
{
@ -327,7 +339,7 @@
"title" : "edt_conf_v4l2_hardware_hue_title",
"default" : 0,
"required" : true,
"propertyOrder" : 32
"propertyOrder" : 33
}
},
"additionalProperties" : true

View File

@ -605,7 +605,8 @@ void HyperionDaemon::handleSettingsUpdate(settings::type settingsType, const QJs
grabberConfig["height"].toInt(0),
grabberConfig["fps"].toInt(15),
grabberConfig["input"].toInt(-1),
grabberConfig["sizeDecimation"].toInt(8));
grabberConfig["sizeDecimation"].toInt(8),
grabberConfig["flip"].toString("auto"));
// Image cropping
_mfGrabber->setCropping(