KDEAmbi/hyperiongrabber.cpp
Tobias J. Endres bff295502f Feat: Increase default change threshold to reduce flickering
Addresses flickering issue by increasing _changeThreshold_m in hyperiongrabber.cpp from 100 to 5000. This filters out subtle pixel variations that caused unnecessary frame updates to WLED.
2025-08-15 22:34:00 +02:00

131 lines
4.5 KiB
C++

#include "hyperiongrabber.h"
#include <QCoreApplication>
#include <QScreen>
#include <QGuiApplication>
#include <QBuffer>
#include <QImage>
#include <QCryptographicHash>
#include <cmath> // For std::abs
// public
HyperionGrabber::HyperionGrabber(QHash<QString, QString> opts)
{
QString addr = "192.168.1.177"; // Default WLED IP
unsigned short port = 21324; // Default WARLS port
unsigned short scale = 8;
unsigned short frameskip = 0;
int inactiveTime = 0;
int changeThreshold = 5000; // Default change threshold
_scale_m = scale;
_frameskip_m = frameskip;
_inactiveTime_m = inactiveTime;
QHashIterator<QString, QString> i(opts);
while (i.hasNext()) {
i.next();
if ((i.key() == "a" || i.key() == "address") && !(i.value().isNull() && i.value().isEmpty())) {
addr = i.value();
} else if ((i.key() == "p" || i.key() == "port") && i.value().toUShort()) {
port = i.value().toUShort();
} else if ((i.key() == "s" || i.key() == "scale") && i.value().toUShort()) {
_scale_m = i.value().toUShort();
} else if ((i.key() == "f" || i.key() == "frameskip") && i.value().toUShort()) {
_frameskip_m = i.value().toUShort();
} else if ((i.key() == "i" || i.key() == "inactive") && i.value().toInt()) {
_inactiveTime_m = (i.value().toInt() * 1000);
} else if ((i.key() == "t" || i.key() == "threshold") && i.value().toInt()) { // New option for threshold
_changeThreshold_m = i.value().toInt();
}
}
#ifdef DEBUG_MODE
_client_p = new DebugClient(this);
#else
_client_p = new WledClient(addr, port, this);
#endif
_waylandGrabber_p = new WaylandGrabber(this);
connect(_waylandGrabber_p, &WaylandGrabber::frameReady, this, &HyperionGrabber::_processFrame);
_waylandGrabber_p->start();
QScreen *screen = QGuiApplication::primaryScreen();
if (screen) {
qDebug() << "Screen size:" << screen->size().width() << "x" << screen->size().height();
} else {
qWarning() << "Could not get primary screen size for Wayland grabber. Defaulting to 1920x1080.";
}
}
HyperionGrabber::~HyperionGrabber()
{
if (_timer_p) {
_timer_p->stop();
delete _timer_p;
}
delete _client_p; // Changed from _wledClient_p
}
// private slots
void HyperionGrabber::_processFrame(const QVideoFrame &frame)
{
if (!frame.isValid()) {
return;
}
_frameCounter_m++;
if (_frameskip_m > 0 && (_frameCounter_m % (_frameskip_m + 1) != 0)) {
return;
}
QImage image = frame.toImage();
if (image.isNull()) {
qWarning() << "Failed to convert QVideoFrame to QImage.";
return;
}
// Calculate target size
QSize targetSize(image.width() / _scale_m, image.height() / _scale_m);
if (!targetSize.isValid()) {
qWarning() << "Invalid target size for scaling.";
return;
}
// Scale the image using Qt's optimized scaling
QImage scaledImage = image.scaled(targetSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
// Convert to a format suitable for WLED (RGB888)
if (scaledImage.format() != QImage::Format_RGB888) {
scaledImage = scaledImage.convertToFormat(QImage::Format_RGB888);
}
// Compare with last scaled image
if (_lastScaledImage_m.isNull() || _lastScaledImage_m.size() != scaledImage.size()) {
// First frame or size changed, send immediately
qDebug() << "First frame or image size changed. Sending to client.";
_client_p->sendImage(scaledImage); // Changed from _wledClient_p
_lastScaledImage_m = scaledImage;
} else {
long long diff = 0;
for (int y = 0; y < scaledImage.height(); ++y) {
for (int x = 0; x < scaledImage.width(); ++x) {
QRgb currentPixel = scaledImage.pixel(x, y);
QRgb lastPixel = _lastScaledImage_m.pixel(x, y);
diff += std::abs(qRed(currentPixel) - qRed(lastPixel));
diff += std::abs(qGreen(currentPixel) - qGreen(lastPixel));
diff += std::abs(qBlue(currentPixel) - qBlue(lastPixel));
}
}
if (diff > _changeThreshold_m) {
qDebug() << "Image changed significantly. Sending to client. Difference:" << diff;
_client_p->sendImage(scaledImage); // Changed from _wledClient_p
_lastScaledImage_m = scaledImage;
} else {
qDebug() << "Image is static (below threshold). Not sending to client. Difference:" << diff;
}
}
}