142 lines
4.7 KiB
C++
142 lines
4.7 KiB
C++
#include "hyperiongrabber.h"
|
|
#include <QCoreApplication>
|
|
#include <QScreen>
|
|
#include <QGuiApplication>
|
|
#include <QBuffer>
|
|
#include <QImage>
|
|
|
|
// public
|
|
|
|
HyperionGrabber::HyperionGrabber(QHash<QString, QString> opts)
|
|
{
|
|
QString addr = "192.168.1.177"; // Default WLED IP
|
|
unsigned short port = 4048; // Default DDP port
|
|
unsigned short scale = 8;
|
|
unsigned short frameskip = 0;
|
|
int inactiveTime = 0;
|
|
|
|
_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);
|
|
}
|
|
}
|
|
|
|
_client_p = new WledClient(addr, port, this);
|
|
|
|
_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;
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
// Ambilight color mapping
|
|
// For demonstration, let's assume a simple layout: 10 LEDs on top, 10 on right, 10 on bottom, 10 on left
|
|
// In a real scenario, this layout would come from configuration (e.g., from wled_config_tool)
|
|
|
|
int ledsTop = 10;
|
|
int ledsRight = 10;
|
|
int ledsBottom = 10;
|
|
int ledsLeft = 10;
|
|
int totalLeds = ledsTop + ledsRight + ledsBottom + ledsLeft;
|
|
|
|
QVector<QColor> ledColors;
|
|
ledColors.reserve(totalLeds);
|
|
|
|
// Calculate average color for each LED region
|
|
// This is a simplified example; actual implementation would involve more precise region calculation
|
|
// and handling of corner LEDs.
|
|
|
|
// Top LEDs
|
|
for (int i = 0; i < ledsTop; ++i) {
|
|
int x = (scaledImage.width() / ledsTop) * i + (scaledImage.width() / ledsTop / 2);
|
|
int y = scaledImage.height() / 2; // Sample from middle of the image height
|
|
ledColors.append(scaledImage.pixelColor(x, y));
|
|
}
|
|
|
|
// Right LEDs
|
|
for (int i = 0; i < ledsRight; ++i) {
|
|
int x = scaledImage.width() / 2; // Sample from middle of the image width
|
|
int y = (scaledImage.height() / ledsRight) * i + (scaledImage.height() / ledsRight / 2);
|
|
ledColors.append(scaledImage.pixelColor(x, y));
|
|
}
|
|
|
|
// Bottom LEDs
|
|
for (int i = 0; i < ledsBottom; ++i) {
|
|
int x = (scaledImage.width() / ledsBottom) * i + (scaledImage.width() / ledsBottom / 2);
|
|
int y = scaledImage.height() / 2; // Sample from middle of the image height
|
|
ledColors.append(scaledImage.pixelColor(x, y));
|
|
}
|
|
|
|
// Left LEDs
|
|
for (int i = 0; i < ledsLeft; ++i) {
|
|
int x = scaledImage.width() / 2; // Sample from middle of the image width
|
|
int y = (scaledImage.height() / ledsLeft) * i + (scaledImage.height() / ledsLeft / 2);
|
|
ledColors.append(scaledImage.pixelColor(x, y));
|
|
}
|
|
|
|
_client_p->setLedsColor(ledColors); // Send all LED colors at once
|
|
}
|