File indexing completed on 2024-05-19 09:23:11

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 <QHash>
0012 #include <QImage>
0013 #include <QObject>
0014 #include <QPoint>
0015 #include <QSharedPointer>
0016 #include <QSize>
0017 #include <optional>
0018 
0019 #include <pipewire/pipewire.h>
0020 #include <spa/param/format-utils.h>
0021 #include <spa/param/props.h>
0022 #include <spa/param/video/format-utils.h>
0023 
0024 #undef Status
0025 
0026 class PipeWireCore;
0027 struct gbm_device;
0028 
0029 typedef void *EGLDisplay;
0030 
0031 struct DmaBufPlane
0032 {
0033     int fd; ///< The dmabuf file descriptor
0034     uint32_t offset; ///< The offset from the start of buffer
0035     uint32_t stride; ///< The distance from the start of a row to the next row in bytes
0036 };
0037 
0038 struct DmaBufAttributes
0039 {
0040     int width = 0;
0041     int height = 0;
0042     uint32_t format = 0;
0043     uint64_t modifier = 0; ///< The layout modifier
0044 
0045     QList<DmaBufPlane> planes;
0046 };
0047 
0048 struct PipeWireCursor
0049 {
0050     QPoint position;
0051     QPoint hotspot;
0052     QImage texture;
0053     bool operator!=(const PipeWireCursor &other) const
0054     {
0055         return !operator==(other);
0056     };
0057     bool operator==(const PipeWireCursor &other) const
0058     {
0059         return position == other.position && hotspot == other.hotspot && texture == other.texture;
0060     }
0061 };
0062 
0063 struct PipeWireFrame
0064 {
0065     spa_video_format format;
0066     std::optional<int> sequential;
0067     std::optional<std::chrono::nanoseconds> presentationTimestamp;
0068     std::optional<DmaBufAttributes> dmabuf;
0069     std::optional<QImage> image;
0070     std::optional<QRegion> damage;
0071     std::optional<PipeWireCursor> cursor;
0072 };
0073 
0074 struct Fraction
0075 {
0076     bool operator==(const Fraction &other) const
0077     {
0078         return numerator == other.numerator && denominator == other.denominator;
0079     }
0080     explicit operator bool() const
0081     {
0082         return isValid();
0083     }
0084     bool isValid() const
0085     {
0086         return denominator > 0;
0087     }
0088     quint32 numerator = 0;
0089     quint32 denominator = 0;
0090 };
0091 
0092 QImage::Format SpaToQImageFormat(quint32 /*spa_video_format*/ format);
0093 
0094 struct PipeWireSourceStreamPrivate;
0095 
0096 class PipeWireSourceStream : public QObject
0097 {
0098     Q_OBJECT
0099 public:
0100     explicit PipeWireSourceStream(QObject *parent = nullptr);
0101     ~PipeWireSourceStream();
0102 
0103     Fraction framerate() const;
0104     void setMaxFramerate(const Fraction &framerate);
0105     uint nodeId();
0106     QString error() const;
0107 
0108     QSize size() const;
0109     pw_stream_state state() const;
0110     bool createStream(uint nodeid, int fd);
0111     void setActive(bool active);
0112     void setDamageEnabled(bool withDamage);
0113 
0114     void handleFrame(struct pw_buffer *buffer);
0115     void process();
0116     void renegotiateModifierFailed(spa_video_format format, quint64 modifier);
0117 
0118     std::optional<std::chrono::nanoseconds> currentPresentationTimestamp() const;
0119 
0120     static uint32_t spaVideoFormatToDrmFormat(spa_video_format spa_format);
0121 
0122     bool usingDmaBuf() const;
0123     bool allowDmaBuf() const;
0124     void setAllowDmaBuf(bool allowed);
0125 
0126 Q_SIGNALS:
0127     void streamReady();
0128     void startStreaming();
0129     void stopStreaming();
0130     void streamParametersChanged();
0131     void frameReceived(const PipeWireFrame &frame);
0132     void stateChanged(pw_stream_state state, pw_stream_state oldState);
0133 
0134 private:
0135     static void onStreamParamChanged(void *data, uint32_t id, const struct spa_pod *format);
0136     static void onStreamStateChanged(void *data, pw_stream_state old, pw_stream_state state, const char *error_message);
0137     static void onRenegotiate(void *data, uint64_t);
0138     QList<const spa_pod *> createFormatsParams(spa_pod_builder podBuilder);
0139 
0140     void coreFailed(const QString &errorMessage);
0141     QScopedPointer<PipeWireSourceStreamPrivate> d;
0142 };