/* SPDX-FileCopyrightText: 2018-2020 Red Hat Inc SPDX-FileCopyrightText: 2020 Aleix Pol Gonzalez SPDX-FileContributor: Jan Grulich SPDX-License-Identifier: LGPL-2.0-or-later */ #pragma once #include "wayland/screencast_v1.h" #include #include #include #include #include #include #include #include #include #include #include namespace KWin { class Cursor; class GLTexture; class PipeWireCore; class ScreenCastBuffer; class ScreenCastSource; struct ScreenCastDmaBufTextureParams { int planeCount = 0; int width = 0; int height = 0; uint32_t format = 0; uint64_t modifier = 0; }; class KWIN_EXPORT ScreenCastStream : public QObject { Q_OBJECT public: explicit ScreenCastStream(ScreenCastSource *source, std::shared_ptr pwCore, QObject *parent); ~ScreenCastStream(); enum class Content { None, Video = 0x1, Cursor = 0x2, }; Q_FLAG(Content) Q_DECLARE_FLAGS(Contents, Content) bool init(); uint framerate(); uint nodeId(); QString error() const { return m_error; } void close(); void scheduleRecord(const QRegion &damage, Contents contents = Content::Video); void setCursorMode(ScreencastV1Interface::CursorMode mode); public Q_SLOTS: void invalidateCursor(); Q_SIGNALS: void ready(quint32 nodeId); void closed(); private: void onStreamParamChanged(uint32_t id, const struct spa_pod *format); void onStreamStateChanged(pw_stream_state old, pw_stream_state state, const char *error_message); void onStreamAddBuffer(pw_buffer *buffer); void onStreamRemoveBuffer(pw_buffer *buffer); bool createStream(); QList buildFormats(bool fixate, char buffer[2048]); void updateParams(); void resize(const QSize &resolution); void coreFailed(const QString &errorMessage); void addCursorMetadata(spa_buffer *spaBuffer, Cursor *cursor); QRegion addCursorEmbedded(ScreenCastBuffer *buffer, Cursor *cursor); void addHeader(spa_buffer *spaBuffer); void corruptHeader(spa_buffer *spaBuffer); void addDamage(spa_buffer *spaBuffer, const QRegion &damagedRegion); void newStreamParams(); spa_pod *buildFormat(struct spa_pod_builder *b, enum spa_video_format format, struct spa_rectangle *resolution, struct spa_fraction *defaultFramerate, struct spa_fraction *minFramerate, struct spa_fraction *maxFramerate, const QList &modifiers, quint32 modifiersFlags); void record(const QRegion &damage, Contents contents); std::optional testCreateDmaBuf(const QSize &size, quint32 format, const QList &modifiers); std::shared_ptr m_pwCore; std::unique_ptr m_source; struct pw_stream *m_pwStream = nullptr; spa_hook m_streamListener; pw_stream_events m_pwStreamEvents = {}; uint32_t m_pwNodeId = 0; QSize m_resolution; bool m_closed = false; spa_video_info_raw m_videoFormat; QString m_error; QList m_modifiers; std::optional m_dmabufParams; // when fixated struct { ScreencastV1Interface::CursorMode mode = ScreencastV1Interface::Hidden; const QSize bitmapSize = QSize(256, 256); QRectF lastRect; std::unique_ptr texture; bool visible = false; bool invalid = true; QMetaObject::Connection changedConnection = QMetaObject::Connection(); QMetaObject::Connection positionChangedConnection = QMetaObject::Connection(); } m_cursor; quint64 m_sequential = 0; bool m_hasDmaBuf = false; quint32 m_drmFormat = 0; std::optional m_lastSent; QRegion m_pendingDamage; QTimer m_pendingFrame; Contents m_pendingContents = Content::None; }; } // namespace KWin Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::ScreenCastStream::Contents)