File indexing completed on 2024-05-05 05:30:19

0001 /*
0002     SPDX-FileCopyrightText: 2018-2020 Red Hat Inc
0003     SPDX-FileCopyrightText: 2020-2021 Aleix Pol Gonzalez <aleixpol@kde.org>
0004     SPDX-FileContributor: Jan Grulich <jgrulich@redhat.com>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #pragma once
0010 
0011 #include <QDebug>
0012 #include <QHash>
0013 #include <QImage>
0014 #include <QObject>
0015 #include <QPoint>
0016 #include <QSharedPointer>
0017 #include <QSize>
0018 #include <optional>
0019 
0020 #include <pipewire/pipewire.h>
0021 #include <spa/param/format-utils.h>
0022 #include <spa/param/props.h>
0023 #include <spa/param/video/format-utils.h>
0024 
0025 #include <kpipewire_export.h>
0026 
0027 #undef Status
0028 
0029 class PipeWireFrameCleanupFunction;
0030 class PipeWireCore;
0031 struct gbm_device;
0032 
0033 typedef void *EGLDisplay;
0034 
0035 struct DmaBufPlane {
0036     int fd; ///< The dmabuf file descriptor
0037     uint32_t offset; ///< The offset from the start of buffer
0038     uint32_t stride; ///< The distance from the start of a row to the next row in bytes
0039 };
0040 
0041 struct DmaBufAttributes {
0042     int width = 0;
0043     int height = 0;
0044     uint32_t format = 0;
0045     uint64_t modifier = 0; ///< The layout modifier
0046 
0047     QList<DmaBufPlane> planes;
0048 };
0049 
0050 struct PipeWireCursor {
0051     QPoint position;
0052     QPoint hotspot;
0053     QImage texture;
0054     bool operator!=(const PipeWireCursor &other) const
0055     {
0056         return !operator==(other);
0057     };
0058     bool operator==(const PipeWireCursor &other) const
0059     {
0060         return position == other.position && hotspot == other.hotspot && texture == other.texture;
0061     }
0062 };
0063 Q_DECLARE_METATYPE(PipeWireCursor);
0064 
0065 class KPIPEWIRE_EXPORT PipeWireFrameData
0066 {
0067     Q_DISABLE_COPY(PipeWireFrameData)
0068 public:
0069     PipeWireFrameData(spa_video_format format, void *data, QSize size, qint32 stride, PipeWireFrameCleanupFunction *cleanup);
0070     ~PipeWireFrameData();
0071 
0072     QImage toImage() const;
0073     std::shared_ptr<PipeWireFrameData> copy() const;
0074 
0075     const spa_video_format format;
0076     void *const data = nullptr;
0077     const QSize size;
0078     const qint32 stride = 0;
0079     PipeWireFrameCleanupFunction *const cleanup = nullptr;
0080 };
0081 
0082 struct KPIPEWIRE_EXPORT PipeWireFrame {
0083     spa_video_format format;
0084     std::optional<quint64> sequential;
0085     std::optional<std::chrono::nanoseconds> presentationTimestamp;
0086     std::optional<DmaBufAttributes> dmabuf;
0087     std::optional<QRegion> damage;
0088     std::optional<PipeWireCursor> cursor;
0089     std::shared_ptr<PipeWireFrameData> dataFrame;
0090 };
0091 
0092 struct Fraction {
0093     bool operator==(const Fraction &other) const
0094     {
0095         return numerator == other.numerator && denominator == other.denominator;
0096     }
0097     explicit operator bool() const
0098     {
0099         return isValid();
0100     }
0101     bool isValid() const
0102     {
0103         return denominator > 0;
0104     }
0105     quint32 numerator = 0;
0106     quint32 denominator = 0;
0107 };
0108 
0109 struct PipeWireSourceStreamPrivate;
0110 
0111 class KPIPEWIRE_EXPORT PipeWireSourceStream : public QObject
0112 {
0113     Q_OBJECT
0114 public:
0115     explicit PipeWireSourceStream(QObject *parent = nullptr);
0116     ~PipeWireSourceStream();
0117 
0118     Fraction framerate() const;
0119     void setMaxFramerate(const Fraction &framerate);
0120     uint nodeId();
0121     QString error() const;
0122 
0123     QSize size() const;
0124     pw_stream_state state() const;
0125     bool createStream(uint nodeid, int fd);
0126     void setActive(bool active);
0127     void setDamageEnabled(bool withDamage);
0128 
0129     void handleFrame(struct pw_buffer *buffer);
0130     void process();
0131     void renegotiateModifierFailed(spa_video_format format, quint64 modifier);
0132 
0133     std::optional<std::chrono::nanoseconds> currentPresentationTimestamp() const;
0134 
0135     static uint32_t spaVideoFormatToDrmFormat(spa_video_format spa_format);
0136 
0137     bool usingDmaBuf() const;
0138     bool allowDmaBuf() const;
0139     void setAllowDmaBuf(bool allowed);
0140 
0141 Q_SIGNALS:
0142     void streamReady();
0143     void startStreaming();
0144     void stopStreaming();
0145     void streamParametersChanged();
0146     void frameReceived(const PipeWireFrame &frame);
0147     void stateChanged(pw_stream_state state, pw_stream_state oldState);
0148 
0149 private:
0150     static void onStreamParamChanged(void *data, uint32_t id, const struct spa_pod *format);
0151     static void onStreamStateChanged(void *data, pw_stream_state old, pw_stream_state state, const char *error_message);
0152     static void onRenegotiate(void *data, uint64_t);
0153     QList<const spa_pod *> createFormatsParams(spa_pod_builder podBuilder);
0154 
0155     void coreFailed(const QString &errorMessage);
0156     QScopedPointer<PipeWireSourceStreamPrivate> d;
0157 };
0158 
0159 Q_DECLARE_METATYPE(QList<DmaBufPlane>);