summaryrefslogtreecommitdiffstats
path: root/pica-client/vaapivideowidget.h
diff options
context:
space:
mode:
authorAnton <anton@picapica.im>2026-08-14 01:29:59 +0400
committerAnton <anton@picapica.im>2026-08-14 01:29:59 +0400
commitad95ec8759777c4b8df0dcd66fd8200d24e912b1 (patch)
treec5da156d51d1839abaa3ae0804ae588ea64a8cf7 /pica-client/vaapivideowidget.h
parent6ef469ba767574384c0373daa5363efb95102ed9 (diff)
downloadpica-pica-ad95ec8759777c4b8df0dcd66fd8200d24e912b1.tar.gz
pica-pica-ad95ec8759777c4b8df0dcd66fd8200d24e912b1.zip
pica-client: VAAPI hardware acceleration
Diffstat (limited to 'pica-client/vaapivideowidget.h')
-rw-r--r--pica-client/vaapivideowidget.h97
1 files changed, 97 insertions, 0 deletions
diff --git a/pica-client/vaapivideowidget.h b/pica-client/vaapivideowidget.h
new file mode 100644
index 0000000..0aebef5
--- /dev/null
+++ b/pica-client/vaapivideowidget.h
@@ -0,0 +1,97 @@
+/*
+ (c) Copyright 2012 - 2026 Anton Sviridenko
+ https://picapica.im
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, version 3.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#ifndef VAAPIVIDEOWIDGET_H
+#define VAAPIVIDEOWIDGET_H
+
+#ifdef HAVE_VAAPI
+
+#include "vaapi.h"
+
+#include <QOpenGLWidget>
+#include <QOpenGLFunctions>
+#include <QOpenGLShaderProgram>
+#include <QString>
+
+// Draws frames that are still sitting in GPU memory as VA surfaces, without
+// bringing them back through system memory on the way.
+//
+// The surface is exported as DMA-BUF file descriptors, imported into EGL as
+// images, and bound to OpenGL textures - one for the luma plane and one for
+// the interleaved chroma plane of an NV12 frame - which a fragment shader
+// then converts to RGB while drawing. Nothing copies the picture; the GPU
+// keeps it where the decoder left it.
+//
+// The alternative, vaPutSurface() onto an X11 Drawable, was not an option
+// here: the client runs on Wayland, where there is no such drawable, and
+// Qt5X11Extras is not installed either. EGL works on both Wayland and X11.
+class VaapiVideoWidget : public QOpenGLWidget, protected QOpenGLFunctions
+{
+ Q_OBJECT
+public:
+ explicit VaapiVideoWidget(QWidget *parent = nullptr);
+ ~VaapiVideoWidget() override;
+
+ // Whether the last frame could actually be drawn. False means the EGL
+ // import failed and nothing is being shown, so a caller can fall back to
+ // the software path rather than leave a blank widget.
+ bool isWorking() const { return m_working; }
+
+public slots:
+ // Takes the frame to draw next, replacing any previous one that has not
+ // been drawn yet - for live video the newest frame is the one that
+ // matters, which is the same policy the decode queue follows.
+ void setFrame(AVFramePtr frame);
+
+ // Drops the current frame and clears the widget.
+ void clearFrame();
+
+signals:
+ // Raised once if the frame cannot be imported for drawing, carrying the
+ // reason. The widget stops trying after that.
+ void renderingFailed(QString message);
+
+protected:
+ void initializeGL() override;
+ void paintGL() override;
+ void resizeGL(int w, int h) override;
+
+private:
+ // Builds the two textures for the current frame out of the surface's
+ // DMA-BUF handles. Returns false and leaves nothing bound on failure.
+ bool importFrame();
+
+ // Releases the EGL images and the file descriptors the export handed
+ // over. Not closing those descriptors leaks them once per frame, which
+ // exhausts the process's descriptors within minutes.
+ void releaseImports();
+
+ AVFramePtr m_frame;
+ QOpenGLShaderProgram *m_program;
+ unsigned int m_textures[2];
+ void *m_images[2];
+ int m_dmabufFds[4];
+ int m_numFds;
+ int m_frameWidth;
+ int m_frameHeight;
+ bool m_working;
+ bool m_reportedFailure;
+ bool m_describedSurface;
+};
+
+#endif // HAVE_VAAPI
+
+#endif // VAAPIVIDEOWIDGET_H