Version 1.0.0
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1 +1,4 @@
|
||||
build/
|
||||
*.tar.gz
|
||||
*.zip
|
||||
*.png
|
||||
@@ -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
28
PKGBUILD
Normal 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
111
README.md
@@ -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 0–255-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 0–255-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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 · <b>S</b> Glättung · "
|
||||
"<b>C</b> Retro · <b>X/+/-</b> Schärfen · "
|
||||
"<b>,/.</b> Helligkeit · <b>1/2</b> HW-Kontrast · "
|
||||
"<b>,/.</b> HW-Helligkeit · <b>1/2</b> HW-Kontrast · "
|
||||
"<b>3/4</b> HW-Sättigung · <b>V</b> Vergleich · "
|
||||
"<b>P</b> Screenshot · <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); }
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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 "
|
||||
"<b>C</b> Retro "
|
||||
"<b>X</b>/<b>+</b>/<b>-</b> Schärfen "
|
||||
"<b>,</b>/<b>.</b> Helligkeit<br>"
|
||||
"<b>,</b>/<b>.</b> HW-Helligkeit<br>"
|
||||
"<b>1</b>/<b>2</b> HW-Kontrast "
|
||||
"<b>3</b>/<b>4</b> HW-Sättigung "
|
||||
"<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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
13
src/main.cpp
13
src/main.cpp
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user