File indexing completed on 2024-11-10 04:57:07

0001 /*
0002     SPDX-FileCopyrightText: 2018-2020 Red Hat Inc
0003     SPDX-FileCopyrightText: 2020 Aleix Pol Gonzalez <aleixpol@kde.org>
0004     SPDX-FileContributor: Jan Grulich <jgrulich@redhat.com>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #pragma once
0010 
0011 #include "config-kwin.h"
0012 
0013 #include "wayland/screencast_v1.h"
0014 
0015 #include <QDateTime>
0016 #include <QHash>
0017 #include <QObject>
0018 #include <QRegion>
0019 #include <QSocketNotifier>
0020 #include <QTimer>
0021 #include <chrono>
0022 #include <memory>
0023 #include <optional>
0024 
0025 #include <pipewire/pipewire.h>
0026 #include <spa/param/format-utils.h>
0027 #include <spa/param/props.h>
0028 #include <spa/param/video/format-utils.h>
0029 
0030 namespace KWin
0031 {
0032 
0033 class Cursor;
0034 class ScreenCastDmaBufTexture;
0035 class EGLNativeFence;
0036 class GLTexture;
0037 class PipeWireCore;
0038 class ScreenCastSource;
0039 
0040 struct ScreenCastDmaBufTextureParams
0041 {
0042     int planeCount = 0;
0043     int width = 0;
0044     int height = 0;
0045     uint32_t format = 0;
0046     uint64_t modifier = 0;
0047 };
0048 
0049 class KWIN_EXPORT ScreenCastStream : public QObject
0050 {
0051     Q_OBJECT
0052 public:
0053     explicit ScreenCastStream(ScreenCastSource *source, std::shared_ptr<PipeWireCore> pwCore, QObject *parent);
0054     ~ScreenCastStream();
0055 
0056     bool init();
0057     uint framerate();
0058     uint nodeId();
0059     QString error() const
0060     {
0061         return m_error;
0062     }
0063 
0064     void stop();
0065 
0066     /**
0067      * Renders @p frame into the current framebuffer into the stream
0068      * @p timestamp
0069      */
0070     void recordFrame(const QRegion &damagedRegion);
0071 
0072     void setCursorMode(ScreencastV1Interface::CursorMode mode, qreal scale, const QRectF &viewport);
0073 
0074 public Q_SLOTS:
0075     void invalidateCursor();
0076     void recordCursor();
0077     bool includesCursor(Cursor *cursor) const;
0078 
0079 Q_SIGNALS:
0080     void streamReady(quint32 nodeId);
0081     void startStreaming();
0082     void stopStreaming();
0083 
0084 private:
0085     void onStreamParamChanged(uint32_t id, const struct spa_pod *format);
0086     void onStreamStateChanged(pw_stream_state old, pw_stream_state state, const char *error_message);
0087     void onStreamAddBuffer(pw_buffer *buffer);
0088     void onStreamRemoveBuffer(pw_buffer *buffer);
0089     void onStreamRenegotiateFormat(uint64_t);
0090 
0091     bool createStream();
0092     QList<const spa_pod *> buildFormats(bool fixate, char buffer[2048]);
0093     void updateParams();
0094     void coreFailed(const QString &errorMessage);
0095     void sendCursorData(Cursor *cursor, spa_meta_cursor *spa_cursor);
0096     void addHeader(spa_buffer *spaBuffer);
0097     void addDamage(spa_buffer *spaBuffer, const QRegion &damagedRegion);
0098     void newStreamParams();
0099     void tryEnqueue(pw_buffer *buffer);
0100     void enqueue();
0101     spa_pod *buildFormat(struct spa_pod_builder *b, enum spa_video_format format, struct spa_rectangle *resolution,
0102                          struct spa_fraction *defaultFramerate, struct spa_fraction *minFramerate, struct spa_fraction *maxFramerate,
0103                          const QList<uint64_t> &modifiers, quint32 modifiersFlags);
0104 
0105     std::optional<ScreenCastDmaBufTextureParams> testCreateDmaBuf(const QSize &size, quint32 format, const QList<uint64_t> &modifiers);
0106     std::shared_ptr<ScreenCastDmaBufTexture> createDmaBufTexture(const ScreenCastDmaBufTextureParams &params);
0107 
0108     std::shared_ptr<PipeWireCore> m_pwCore;
0109     std::unique_ptr<ScreenCastSource> m_source;
0110     struct pw_stream *m_pwStream = nullptr;
0111     struct spa_source *m_pwRenegotiate = nullptr;
0112     spa_hook m_streamListener;
0113     pw_stream_events m_pwStreamEvents = {};
0114 
0115     uint32_t m_pwNodeId = 0;
0116 
0117     QSize m_resolution;
0118     bool m_stopped = false;
0119     bool m_streaming = false;
0120 
0121     spa_video_info_raw m_videoFormat;
0122     QString m_error;
0123     QList<uint64_t> m_modifiers;
0124     std::optional<ScreenCastDmaBufTextureParams> m_dmabufParams; // when fixated
0125 
0126     struct
0127     {
0128         ScreencastV1Interface::CursorMode mode = ScreencastV1Interface::Hidden;
0129         const QSize bitmapSize = QSize(256, 256);
0130         qreal scale = 1;
0131         QRectF viewport;
0132         QRectF lastRect;
0133         std::unique_ptr<GLTexture> texture;
0134         bool visible = false;
0135         bool invalid = true;
0136     } m_cursor;
0137 
0138     QHash<struct pw_buffer *, std::shared_ptr<ScreenCastDmaBufTexture>> m_dmabufDataForPwBuffer;
0139 
0140     pw_buffer *m_pendingBuffer = nullptr;
0141     std::unique_ptr<QSocketNotifier> m_pendingNotifier;
0142     std::unique_ptr<EGLNativeFence> m_pendingFence;
0143     quint64 m_sequential = 0;
0144     bool m_hasDmaBuf = false;
0145     bool m_waitForNewBuffers = false;
0146     quint32 m_drmFormat = 0;
0147 
0148     QDateTime m_lastSent;
0149     QRegion m_pendingDamages;
0150     QTimer m_pendingFrame;
0151 };
0152 
0153 } // namespace KWin