#pragma once #include #include #include #include QT_BEGIN_NAMESPACE class QOpenGLShaderProgram; class QOpenGLTexture; QT_END_NAMESPACE // VideoWidget zeichnet das eingehende Frame per OpenGL (statt QPainter/CPU). // Zwei unabhängige Effekte können live per Shader zugeschaltet werden: // Bildglättung (Chroma/Luma-Rekonstruktion gegen Scaler-Artefakte, echte // Bildverbesserung) und Retro-Optik (Scanlines/Maske/Wölbung, Nostalgie-Look). // QOpenGLExtraFunctions (statt nur QOpenGLFunctions) wird benötigt, weil // Vertex-Array-Objects (glGenVertexArrays & Co.) nicht Teil des reinen // ES2-kompatiblen QOpenGLFunctions-Subsets sind. class VideoWidget : public QOpenGLWidget, protected QOpenGLExtraFunctions { Q_OBJECT public: explicit VideoWidget(QWidget* parent = nullptr); ~VideoWidget() override; public slots: void setFrame(const QImage& image); void setSmoothModeEnabled(bool enabled); void setRetroModeEnabled(bool enabled); void setSharpenAmount(float amount); void setBrightness(float gamma); void setRawEnabled(bool enabled); void setCompareEnabled(bool enabled); bool smoothModeEnabled() const { return m_smoothEnabled; } bool retroModeEnabled() const { return m_retroEnabled; } float sharpenAmount() const { return m_sharpenAmount; } float brightness() const { return m_brightness; } bool rawEnabled() const { return m_rawEnabled; } bool compareEnabled() const { return m_compareEnabled; } QImage grabProcessedFrame() { return grabFramebuffer(); } protected: void initializeGL() override; void resizeGL(int w, int h) override; void paintGL() override; private: void uploadPendingFrame(); void drawNoSignal(); QOpenGLShaderProgram* m_program = nullptr; QOpenGLTexture* m_texture = nullptr; unsigned int m_vbo = 0; unsigned int m_vao = 0; QImage m_pendingImage; // Wartet auf Upload im GL-Thread (paintGL) bool m_pendingDirty = false; QSize m_imageSize; // Auflösung des zuletzt hochgeladenen Frames bool m_hasFrame = false; bool m_smoothEnabled = true; // Bildglättung: Chroma/Luma-Rekonstruktion gegen Scaler-Artefakte bool m_retroEnabled = false; // Retro-Optik: Scanlines/Maske/Wölbung (Nostalgie-Look) float m_sharpenAmount = 0.0f; // Nachschärfen (Unsharp Mask): 0 = aus float m_brightness = 1.0f; // Gamma-Faktor: 1.0 = neutral, >1 heller, <1 dunkler bool m_rawEnabled = false; // Diagnose: umgeht ALLES (Studio-Range, Kontrast, Sättigung, Gamma) bool m_compareEnabled = false; // Live-Vergleich: links roh, rechts bearbeitet public: static constexpr float kBrightnessMin = 0.4f; static constexpr float kBrightnessMax = 3.2f; static constexpr float kBrightnessStep = 0.1f; static constexpr float kSharpenMin = 0.0f; static constexpr float kSharpenMax = 20.0f; static constexpr float kSharpenStep = 0.5f; static constexpr float kSharpenDefault = 2.5f; // Wert für Taste X (Quick-Toggle) };