Version 1.0.0

This commit is contained in:
2026-09-05 23:00:30 +02:00
parent cc3527f86a
commit d1de850b60
11 changed files with 171 additions and 102 deletions

3
.gitignore vendored
View File

@@ -1 +1,4 @@
build/
*.tar.gz
*.zip
*.png

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.16)
project(HDMIViewer VERSION 1.4.0 LANGUAGES CXX)
project(HDMIViewer VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

28
PKGBUILD Normal file
View File

@@ -0,0 +1,28 @@
# Maintainer: Dany Thinnes <dany@projekt-hirnfrei.de>
pkgname=hdmi-viewer
pkgver=1.0.0
pkgrel=1
pkgdesc="Schlanker Qt6/C++ Live-Viewer für HDMI-Grabber (V4L2 + ALSA), Companion zu OBS Studio"
arch=('x86_64')
url="https://git.projekt-hirnfrei.de/diabolus/hdmiviewer"
license=('MIT')
depends=('qt6-base' 'alsa-lib')
makedepends=('cmake')
source=("$pkgname-$pkgver.tar.gz::$url/archive/v$pkgver.tar.gz")
sha256sums=('SKIP')
build() {
# Der Ordnername im Archiv hängt von der Gitea-Instanz ab (meist
# "hdmiviewer", nicht versioniert) - daher robust per Glob statt fest
# verdrahtetem Pfad.
cd "$srcdir"/*/
cmake -B build -S . \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr
cmake --build build
}
package() {
cd "$srcdir"/*/
DESTDIR="$pkgdir" cmake --install build
}

111
README.md
View File

@@ -5,52 +5,83 @@ Gedacht als Companion zu OBS Studio: **Anzeigen ohne Aufnehmen**.
## Features
- Live-Vorschau vom HDMI-Grabber via V4L2 (YUYV und NV12)
- ALSA-Audio direkt vom Grabber-Gerät
- Gerät-Auswahl beim Start, **Audio-Gerät wird gespeichert**
- Live-Vorschau vom HDMI-Grabber via V4L2, mit automatischer Formatpriorität
MJPEG → YUYV → NV12 (MJPEG braucht deutlich weniger USB-Bandbreite und
erlaubt so höhere Auflösungen/Framerates)
- ALSA-Audio direkt vom Grabber-Gerät (Capture → Wiedergabe, per Thread)
- Gerät-Auswahl beim Start (Video, Audio, Ziel-Framerate), alle Einstellungen
werden gespeichert und beim nächsten Start vorausgewählt
- **F** → Vollbild / **F** oder **Esc** im Vollbild → Fenstermodus
- **Esc** im Fenstermodus → zurück zur Gerät-Auswahl (Device wird sauber freigegeben)
- Seitenverhältnis immer bewahrt (Letterbox/Pillarbox)
- Titelleiste zeigt tatsächliche Auflösung und FPS
- Colorspace-Konvertierung im ThreadPool (kein Ruckeln)
- FPS explizit auf 60fps gesetzt (was Grabber liefert wird in Statusbar angezeigt)
- **Bildglättung** (standardmäßig an): GPU-Shader trennt Luma/Chroma und
behandelt sie getrennt Chroma wird stärker weichgezeichnet (killt
Dot-Crawl/Farbrauschen billiger Composite→HDMI-Scaler wie Lioncast Mini
AV2HDMI o.ä.), Luma wird leicht geglättet und dezent gegengeschärft
(nimmt harte Scaler-Kanten raus, ohne matschig zu wirken). Keine Optik-
Spielerei, sondern eine echte Bildverbesserung. Taste **S** zum Umschalten.
- **Retro-Optik** (standardmäßig aus): separater Nostalgie-Look Scanlines,
Phosphor-/Aperture-Grille-Maske, leichte Wölbung wie bei einem alten
Röhrenfernseher. Lässt sich mit der Bildglättung kombinieren. Taste **C**.
- **Helligkeit** (Tasten **,** dunkler / **.** heller): Gamma-Anpassung, live
und persistiert. Sinnvoll als Feinjustierung, falls Farbraum-Erkennung
(siehe unten) allein nicht perfekt zum eigenen Bildschirm passt.
- **Hardware-Helligkeit**: Beim Öffnen des Geräts wird (falls vom Chip
unterstützt) der V4L2-Brightness-Regler direkt am Grabber moderat
angehoben (+20 % des Wertebereichs ab Werkseinstellung) das wirkt
bereits VOR der JPEG-Kompression und kann so tatsächlich verlorene
Schattendetails retten, statt nur nachträglich zu strecken, was von der
Kompression übrig blieb. Diagnose-Ausgabe der verfügbaren Regler landet
beim Start im Terminal.
- Titelleiste und Statusleiste zeigen tatsächliche Auflösung, FPS und Pixelformat
- GPU-Rendering per OpenGL 3.3 (kein Ruckeln durch CPU-seitiges Skalieren)
- **Bildglättung** (standardmäßig an, Taste **S**): GPU-Shader trennt Luma/Chroma
und behandelt sie getrennt Chroma wird stärker weichgezeichnet (killt
Dot-Crawl/Farbrauschen billiger Composite→HDMI-Scaler), Luma wird leicht
geglättet und dezent gegengeschärft (nimmt harte Scaler-Kanten raus, ohne
matschig zu wirken). Keine Optik-Spielerei, sondern eine echte Bildverbesserung.
- **Retro-Optik** (standardmäßig aus, Taste **C**): separater Nostalgie-Look
Scanlines, Phosphor-/Aperture-Grille-Maske, leichte Wölbung wie bei einem
alten Röhrenfernseher. Lässt sich mit der Bildglättung kombinieren.
- **Nachschärfen** (Unsharp Mask, Taste **X** zum Umschalten, **+**/**-** zum
Fein-Justieren): unabhängig von der Bildglättung, live einstellbar und
persistiert.
- **Hardware-Helligkeit/-Kontrast/-Sättigung** (Tasten **,**/**.**, **1**/**2**,
**3**/**4**): steuert die entsprechenden V4L2-Regler *direkt am
Grabber-Chip*, also VOR der JPEG-Kompression das rettet tatsächlich
Schattendetails, statt nur nachträglich am fertig komprimierten Bild zu
strecken (was sichtbare Artefakte/Banding erzeugt). Beim Start wird der
jeweilige Ausgangswert des Chips ausgelesen und gemerkt; beim Beenden wird
er exakt wiederhergestellt, sodass der Grabber für andere Programme
unverändert bleibt. Im Startdialog lassen sich für alle drei Regler feste
Zielwerte vorgeben (`unverändert` = Regler beim Start gar nicht anfassen).
- **Studio-/Full-Range-Korrektur**: Das fertig dekodierte Bild wird von einem
komprimierten Kontrastumfang (Schwarzpunkt niedrig angesetzt, Weißpunkt
≈235/255) auf den vollen 0255-Kontrastumfang gedehnt. Ohne diese
Korrektur wirkt das Bild dumpf, kontrastarm und zu dunkel viele billige
HDMI-Grabber liefern (oder kodieren, auch bei MJPEG) genau in diesem
komprimierten Bereich. Greift direkt im GPU-Shader auf dem fertigen
RGB-Bild, also unabhängig vom Pixelformat.
≈235/255) auf den vollen 0255-Kontrastumfang gedehnt. Ohne diese Korrektur
wirkt das Bild dumpf, kontrastarm und zu dunkel viele billige HDMI-Grabber
liefern (oder kodieren, auch bei MJPEG) genau in diesem komprimierten
Bereich. Greift direkt im GPU-Shader auf dem fertigen RGB-Bild, also
unabhängig vom Pixelformat.
- **Roh-Modus** (Taste **R**): Diagnose-Umschalter, der sämtliche Verarbeitung
(Bildglättung, Retro-Optik, Studio-Range-Korrektur, Kontrast-/
Sättigungs-Punch, Gamma) umgeht und das Bild 1:1 anzeigt.
- **Live-Vergleich** (Taste **V**): zeigt links das rohe und rechts das
bearbeitete Bild nebeneinander praktisch zum Fein-Tunen der Hardware-Regler.
- **Screenshot** (Taste **P**): speichert das aktuell angezeigte (bearbeitete)
Frame als PNG im Home-Verzeichnis.
- **Frame-Dump** (Taste **D**, nur bei MJPEG): speichert das nächste rohe,
unveränderte MJPEG-Frame direkt vom Chip als JPEG nützlich, um zu prüfen,
ob Abweichungen schon in den Rohdaten liegen oder erst bei der eigenen
Verarbeitung entstehen.
## Abhängigkeiten (Arch Linux)
```bash
sudo pacman -S qt6-base cmake alsa-lib linux-headers base-devel
sudo pacman -S qt6-base cmake alsa-lib base-devel
```
`qt6-base` bringt auf Arch bereits die benötigten `Qt6OpenGL`- und
`Qt6OpenGLWidgets`-Module mit.
`Qt6OpenGLWidgets`-Module mit. `linux/videodev2.h` ist Teil von
`linux-api-headers`, das über die `base`-Gruppe ohnehin installiert ist.
## Bauen
## Installation über AUR
```bash
yay -S hdmi-viewer
# oder mit einem anderen AUR-Helper, bzw. manuell:
git clone https://aur.archlinux.org/hdmi-viewer.git
cd hdmi-viewer
makepkg -si
```
## Quellcode
```bash
git clone https://git.projekt-hirnfrei.de/diabolus/hdmiviewer.git
```
## Manuell bauen
```bash
mkdir build && cd build
@@ -67,12 +98,20 @@ make -j$(nproc)
## Tastenkürzel
| Taste | Funktion |
|--------------|---------------------------------------------|
|---------|--------------------------------------------------------|
| F | Vollbild ein/aus |
| S | Bildglättung ein/aus |
| C | Retro-Optik (Scanlines/Maske) ein/aus |
| , / . | Dunkler / Heller (Helligkeit, gespeichert) |
| Esc | Vollbild verlassen ODER zurück zum Dialog |
| X | Nachschärfen ein/aus (letzter Wert ↔ aus) |
| + / - | Nachschärfen stärker / schwächer |
| , / . | Hardware-Helligkeit dunkler / heller |
| 1 / 2 | Hardware-Kontrast runter / hoch |
| 3 / 4 | Hardware-Sättigung runter / hoch |
| R | Roh-Modus (Diagnose, alle Effekte umgangen) ein/aus |
| V | Live-Vergleich (links roh, rechts bearbeitet) ein/aus |
| P | Screenshot speichern (PNG) |
| D | Rohes MJPEG-Frame dumpen (Diagnose) |
| Esc | Vollbild verlassen ODER zurück zum Gerätedialog |
## Einstellungen

View File

@@ -392,7 +392,7 @@ void CaptureThread::restoreHardwareControls()
qDebug().noquote() << "Hardware-Regler auf Ausgangswerte zurückgesetzt.";
}
// Für Live-Tasten (Kontrast/Sättigung): liest den aktuellen Wert, addiert
// Für Live-Tasten (Helligkeit/Kontrast/Sättigung): liest den aktuellen Wert, addiert
// delta, schreibt zurück, merkt sich den neuen Wert dauerhaft und meldet
// ihn per Signal (für die Einblendung in der UI).
void CaptureThread::adjustHardwareControl(quint32 id, const char* settingsKey,
@@ -422,6 +422,11 @@ void CaptureThread::adjustHardwareControl(quint32 id, const char* settingsKey,
}
}
void CaptureThread::adjustHardwareBrightness(int delta)
{
adjustHardwareControl(V4L2_CID_BRIGHTNESS, "hardware/brightness", "Hardware-Helligkeit", delta);
}
void CaptureThread::adjustHardwareContrast(int delta)
{
adjustHardwareControl(V4L2_CID_CONTRAST, "hardware/contrast", "Hardware-Kontrast", delta);

View File

@@ -24,6 +24,7 @@ public:
void stopAndWait();
void requestFrameDump(); // speichert das nächste rohe MJPEG-Frame unverändert auf die Platte
void adjustHardwareBrightness(int delta);
void adjustHardwareContrast(int delta);
void adjustHardwareSaturation(int delta);

View File

@@ -1,5 +1,5 @@
#include "DeviceDialog.h"
#include "VideoWidget.h" // für kBrightnessMin/Max, kSharpenMin/Max (eine Quelle der Wahrheit)
#include "VideoWidget.h" // für kSharpenMin/Max (eine Quelle der Wahrheit)
#include <QVBoxLayout>
#include <QHBoxLayout>
@@ -85,16 +85,17 @@ DeviceDialog::DeviceDialog(QWidget* parent)
"0 = aus. Im laufenden Betrieb mit [X]/[+]/[-] änderbar.");
form->addRow("Nachschärfen:", m_sharpenSpin);
m_brightnessSpin = new QDoubleSpinBox(this);
m_brightnessSpin->setRange(VideoWidget::kBrightnessMin * 100.0, VideoWidget::kBrightnessMax * 100.0);
m_brightnessSpin->setSingleStep(VideoWidget::kBrightnessStep * 100.0);
m_brightnessSpin->setDecimals(0);
m_brightnessSpin->setSuffix(" %");
m_brightnessSpin->setValue(100.0);
m_brightnessSpin->setToolTip(
"Gamma-Helligkeit, 100 % = unverändert. Im laufenden Betrieb\n"
"mit [,]/[.] änderbar.");
form->addRow("Helligkeit:", m_brightnessSpin);
m_hwBrightnessSpin = new QSpinBox(this);
m_hwBrightnessSpin->setRange(-1, 100);
m_hwBrightnessSpin->setValue(-1);
m_hwBrightnessSpin->setSpecialValueText("unverändert");
m_hwBrightnessSpin->setToolTip(
"Hardware-Helligkeit direkt am Grabber-Chip, VOR der JPEG-Kompression\n"
"(Wertebereich hängt vom jeweiligen Chip ab, hier 0-100 angenommen).\n"
"\"unverändert\" lässt den aktuellen Chip-Wert einfach in Ruhe.\n"
"Im laufenden Betrieb mit [,]/[.] änderbar. hdmi-viewer merkt sich\n"
"beim Start den Ausgangswert und stellt ihn beim Beenden wieder her.");
form->addRow("Hardware-Helligkeit:", m_hwBrightnessSpin);
m_hwContrastSpin = new QSpinBox(this);
m_hwContrastSpin->setRange(-1, 100);
@@ -125,7 +126,7 @@ DeviceDialog::DeviceDialog(QWidget* parent)
"Titelleiste angezeigt.<br>"
"<b>F</b> Vollbild &nbsp;·&nbsp; <b>S</b> Glättung &nbsp;·&nbsp; "
"<b>C</b> Retro &nbsp;·&nbsp; <b>X/+/-</b> Schärfen &nbsp;·&nbsp; "
"<b>,/.</b> Helligkeit &nbsp;·&nbsp; <b>1/2</b> HW-Kontrast &nbsp;·&nbsp; "
"<b>,/.</b> HW-Helligkeit &nbsp;·&nbsp; <b>1/2</b> HW-Kontrast &nbsp;·&nbsp; "
"<b>3/4</b> HW-Sättigung &nbsp;·&nbsp; <b>V</b> Vergleich &nbsp;·&nbsp; "
"<b>P</b> Screenshot &nbsp;·&nbsp; <b>Esc</b> zurück hierher</small>",
this);
@@ -156,7 +157,7 @@ int DeviceDialog::selectedFps() const { return m_fpsCombo->currentDa
bool DeviceDialog::selectedSmoothMode() const { return m_smoothCheck->isChecked(); }
bool DeviceDialog::selectedRetroMode() const { return m_retroCheck->isChecked(); }
float DeviceDialog::selectedSharpenAmount() const { return static_cast<float>(m_sharpenSpin->value()); }
float DeviceDialog::selectedBrightness() const { return static_cast<float>(m_brightnessSpin->value() / 100.0); }
int DeviceDialog::selectedHwBrightness() const { return m_hwBrightnessSpin->value(); }
int DeviceDialog::selectedHwContrast() const { return m_hwContrastSpin->value(); }
int DeviceDialog::selectedHwSaturation() const { return m_hwSaturationSpin->value(); }
@@ -166,7 +167,7 @@ void DeviceDialog::setPreselectedFps(int fps) { selectByData(m_fpsCombo, QString
void DeviceDialog::setPreselectedSmoothMode(bool enabled) { m_smoothCheck->setChecked(enabled); }
void DeviceDialog::setPreselectedRetroMode(bool enabled) { m_retroCheck->setChecked(enabled); }
void DeviceDialog::setPreselectedSharpenAmount(float amount) { m_sharpenSpin->setValue(amount); }
void DeviceDialog::setPreselectedBrightness(float gamma) { m_brightnessSpin->setValue(gamma * 100.0); }
void DeviceDialog::setPreselectedHwBrightness(int value) { m_hwBrightnessSpin->setValue(value); }
void DeviceDialog::setPreselectedHwContrast(int value) { m_hwContrastSpin->setValue(value); }
void DeviceDialog::setPreselectedHwSaturation(int value) { m_hwSaturationSpin->setValue(value); }

View File

@@ -23,7 +23,7 @@ public:
bool selectedSmoothMode() const;
bool selectedRetroMode() const;
float selectedSharpenAmount() const;
float selectedBrightness() const;
int selectedHwBrightness() const; // -1 = unverändert lassen
int selectedHwContrast() const; // -1 = unverändert lassen
int selectedHwSaturation() const; // -1 = unverändert lassen
@@ -33,7 +33,7 @@ public:
void setPreselectedSmoothMode(bool enabled);
void setPreselectedRetroMode(bool enabled);
void setPreselectedSharpenAmount(float amount);
void setPreselectedBrightness(float gamma);
void setPreselectedHwBrightness(int value); // -1 = unverändert
void setPreselectedHwContrast(int value); // -1 = unverändert
void setPreselectedHwSaturation(int value); // -1 = unverändert
@@ -48,7 +48,7 @@ private:
QCheckBox* m_smoothCheck = nullptr;
QCheckBox* m_retroCheck = nullptr;
QDoubleSpinBox* m_sharpenSpin = nullptr;
QDoubleSpinBox* m_brightnessSpin = nullptr;
QSpinBox* m_hwBrightnessSpin = nullptr;
QSpinBox* m_hwContrastSpin = nullptr;
QSpinBox* m_hwSaturationSpin = nullptr;
};

View File

@@ -25,7 +25,6 @@ MainWindow::MainWindow(const QString& videoDevice,
int targetFps,
bool smoothModeEnabled,
bool retroModeEnabled,
float brightness,
float sharpenAmount,
float lastSharpenAmount,
QWidget* parent)
@@ -41,7 +40,6 @@ MainWindow::MainWindow(const QString& videoDevice,
m_video->setSmoothModeEnabled(smoothModeEnabled);
m_video->setRetroModeEnabled(retroModeEnabled);
m_video->setSharpenAmount(sharpenAmount);
m_video->setBrightness(brightness);
setCentralWidget(m_video);
// Kurzzeitige Einblendung unten links (funktioniert auch im Vollbild,
@@ -118,11 +116,11 @@ void MainWindow::setupMenuBar()
viewMenu->addSeparator();
QAction* brighterAct = viewMenu->addAction("Heller\t.");
connect(brighterAct, &QAction::triggered, this, &MainWindow::increaseBrightness);
QAction* brighterAct = viewMenu->addAction("Heller (Hardware)\t.");
connect(brighterAct, &QAction::triggered, this, &MainWindow::increaseHwBrightness);
QAction* darkerAct = viewMenu->addAction("Dunkler\t,");
connect(darkerAct, &QAction::triggered, this, &MainWindow::decreaseBrightness);
QAction* darkerAct = viewMenu->addAction("Dunkler (Hardware)\t,");
connect(darkerAct, &QAction::triggered, this, &MainWindow::decreaseHwBrightness);
viewMenu->addSeparator();
@@ -230,14 +228,20 @@ void MainWindow::applySharpen(float value)
showOverlayMessage(QString("Nachschärfen: %1").arg(value, 0, 'f', 1));
}
void MainWindow::increaseBrightness()
void MainWindow::increaseHwBrightness()
{
applyBrightness(m_video->brightness() + VideoWidget::kBrightnessStep);
if (m_capture)
{
m_capture->adjustHardwareBrightness(5);
}
}
void MainWindow::decreaseBrightness()
void MainWindow::decreaseHwBrightness()
{
applyBrightness(m_video->brightness() - VideoWidget::kBrightnessStep);
if (m_capture)
{
m_capture->adjustHardwareBrightness(-5);
}
}
void MainWindow::toggleRaw()
@@ -279,19 +283,6 @@ void MainWindow::saveScreenshot()
}
}
void MainWindow::applyBrightness(float value)
{
value = qBound(VideoWidget::kBrightnessMin, value, VideoWidget::kBrightnessMax);
m_video->setBrightness(value);
QSettings settings;
settings.setValue("display/brightness", static_cast<double>(value));
statusBar()->showMessage(
QString("Helligkeit: %1 %").arg(qRound(value * 100.0f)), 2000);
showOverlayMessage(QString("Helligkeit: %1 %").arg(qRound(value * 100.0f)));
}
void MainWindow::showAbout()
{
auto* dlg = new QDialog(this);
@@ -345,7 +336,7 @@ void MainWindow::showAbout()
grid->addWidget(v, row, 1);
};
addRow(0, "Version", "1.4.0");
addRow(0, "Version", "1.0");
addRow(1, "Entwickler", "Dany Thinnes");
addRow(2, "Projekt", "Projekt Hirnfrei");
addRow(3, "Framework", QString("Qt %1").arg(QT_VERSION_STR));
@@ -365,7 +356,7 @@ void MainWindow::showAbout()
"<b>S</b> Glättung &nbsp;&nbsp; "
"<b>C</b> Retro &nbsp;&nbsp; "
"<b>X</b>/<b>+</b>/<b>-</b> Schärfen &nbsp;&nbsp; "
"<b>,</b>/<b>.</b> Helligkeit<br>"
"<b>,</b>/<b>.</b> HW-Helligkeit<br>"
"<b>1</b>/<b>2</b> HW-Kontrast &nbsp;&nbsp; "
"<b>3</b>/<b>4</b> HW-Sättigung &nbsp;&nbsp; "
"<b>R</b> Roh-Diagnose<br>"
@@ -442,10 +433,10 @@ void MainWindow::keyPressEvent(QKeyEvent* event)
decreaseSharpen();
break;
case Qt::Key_Period:
increaseBrightness();
increaseHwBrightness();
break;
case Qt::Key_Comma:
decreaseBrightness();
decreaseHwBrightness();
break;
case Qt::Key_R:
toggleRaw();
@@ -503,7 +494,7 @@ void MainWindow::updateStatusBar()
info = QString("%1×%2 @ %3fps %4 ")
.arg(m_capWidth).arg(m_capHeight).arg(m_capFps).arg(m_capFmt);
info += QString("Video: %1 Audio: %2 [F] Vollbild [S] Glättung [C] Retro [X/+/-] Schärfen [,/.] Helligkeit [1/2] HW-Kontrast [3/4] HW-Sättigung [R] Roh [V] Vergleich [P] Screenshot [D] Frame dumpen [Esc] Einstellungen")
info += QString("Video: %1 Audio: %2 [F] Vollbild [S] Glättung [C] Retro [X/+/-] Schärfen [,/.] HW-Helligkeit [1/2] HW-Kontrast [3/4] HW-Sättigung [R] Roh [V] Vergleich [P] Screenshot [D] Frame dumpen [Esc] Einstellungen")
.arg(m_videoDevice,
m_audioDevice.isEmpty() ? QStringLiteral("") : m_audioDevice);

View File

@@ -21,7 +21,6 @@ public:
int targetFps,
bool smoothModeEnabled = true,
bool retroModeEnabled = false,
float brightness = 1.0f,
float sharpenAmount = 0.0f,
float lastSharpenAmount = 2.5f,
QWidget* parent = nullptr);
@@ -44,8 +43,8 @@ private slots:
void toggleSharpen();
void increaseSharpen();
void decreaseSharpen();
void increaseBrightness();
void decreaseBrightness();
void increaseHwBrightness();
void decreaseHwBrightness();
void toggleRaw();
void toggleCompare();
void saveScreenshot();
@@ -55,7 +54,6 @@ private:
void toggleFullscreen();
void stopAll();
void updateStatusBar();
void applyBrightness(float value);
void applySharpen(float value);
void showOverlayMessage(const QString& text);

View File

@@ -18,7 +18,7 @@ int main(int argc, char* argv[])
QApplication app(argc, argv);
app.setApplicationName("HDMIViewer");
app.setApplicationVersion("1.4.0");
app.setApplicationVersion("1.0");
app.setOrganizationName("hdmi-viewer");
QSettings settings;
@@ -31,7 +31,7 @@ int main(int argc, char* argv[])
dlg.setPreselectedSmoothMode(settings.value("display/smooth", true).toBool());
dlg.setPreselectedRetroMode(settings.value("display/retro", false).toBool());
dlg.setPreselectedSharpenAmount(settings.value("display/sharpen", 0.0).toFloat());
dlg.setPreselectedBrightness(settings.value("display/brightness", 1.0).toFloat());
dlg.setPreselectedHwBrightness(settings.value("hardware/brightness", -1).toInt());
dlg.setPreselectedHwContrast(settings.value("hardware/contrast", -1).toInt());
dlg.setPreselectedHwSaturation(settings.value("hardware/saturation", -1).toInt());
@@ -44,7 +44,7 @@ int main(int argc, char* argv[])
const bool smoothMode = dlg.selectedSmoothMode();
const bool retroMode = dlg.selectedRetroMode();
const float sharpenAmt = dlg.selectedSharpenAmount();
const float brightness = dlg.selectedBrightness();
const int hwBrightness = dlg.selectedHwBrightness();
const int hwContrast = dlg.selectedHwContrast();
const int hwSaturation = dlg.selectedHwSaturation();
// Für die Taste [X] (Quick-Toggle 0 ↔ letzter Wert) zur Laufzeit:
@@ -66,11 +66,14 @@ int main(int argc, char* argv[])
settings.setValue("display/smooth", smoothMode);
settings.setValue("display/retro", retroMode);
settings.setValue("display/sharpen", static_cast<double>(sharpenAmt));
settings.setValue("display/brightness", static_cast<double>(brightness));
if (sharpenAmt > 0.0f)
settings.setValue("display/sharpen_last", static_cast<double>(sharpenAmt));
// -1 = "unverändert" -> kein expliziter Nutzerwert, Regler bleibt
// beim Öffnen unangetastet (siehe CaptureThread::applyHardwareControls)
if (hwBrightness >= 0)
settings.setValue("hardware/brightness", hwBrightness);
else
settings.remove("hardware/brightness");
if (hwContrast >= 0)
settings.setValue("hardware/contrast", hwContrast);
else
@@ -81,7 +84,7 @@ int main(int argc, char* argv[])
settings.remove("hardware/saturation");
settings.sync();
MainWindow win(videoDevice, audioDevice, fps, smoothMode, retroMode, brightness, sharpenAmt, lastSharpen);
MainWindow win(videoDevice, audioDevice, fps, smoothMode, retroMode, sharpenAmt, lastSharpen);
win.show();
app.exec();