File indexing completed on 2024-06-23 05:24:07

0001 // SPDX-FileCopyrightText: 2023 Arjen Hiemstra <ahiemstra@heimr.nl>
0002 //
0003 // SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0004 
0005 #pragma once
0006 
0007 #include <memory>
0008 #include <optional>
0009 
0010 #include <QImage>
0011 #include <QObject>
0012 #include <QPoint>
0013 #include <QRegion>
0014 #include <QSize>
0015 
0016 #include <freerdp/server/rdpgfx.h>
0017 
0018 #include "krdp_export.h"
0019 
0020 namespace KRdp
0021 {
0022 
0023 class RdpConnection;
0024 
0025 /**
0026  * A frame of compressed video data.
0027  */
0028 struct VideoFrame {
0029     /**
0030      * The size of the frame, in pixels.
0031      */
0032     QSize size;
0033     /**
0034      * h264 compressed data in YUV420 color space.
0035      */
0036     QByteArray data;
0037     /**
0038      * Area of the frame that was actually damaged.
0039      * TODO: Actually use this information.
0040      */
0041     QRegion damage;
0042     /**
0043      * Whether the packet contains all the information
0044      */
0045     bool isKeyFrame;
0046     /**
0047      * When was this frame presented.
0048      */
0049     std::chrono::system_clock::time_point presentationTimeStamp;
0050 };
0051 
0052 /**
0053  * A class that encapsulates an RdpGfx video stream.
0054  *
0055  * Video streaming is done using the "RDP Graphics Pipeline" protocol
0056  * extension which allows using h264 as the codec for the video stream.
0057  * However, this protocol extension is fairly complex to setup and use.
0058  *
0059  * VideoStream makes sure to handle most of the complexity of the RdpGfx
0060  * protocol like ensuring the client knows the right resolution and a
0061  * surface at the right size. It also takes care of sending the frames,
0062  * using a separate thread for a submission queue.
0063  *
0064  * VideoStream is managed by Session. Each session will have one instance
0065  * of this class.
0066  */
0067 class KRDP_EXPORT VideoStream : public QObject
0068 {
0069     Q_OBJECT
0070 
0071 public:
0072     explicit VideoStream(RdpConnection *session);
0073     ~VideoStream() override;
0074 
0075     bool initialize();
0076     void close();
0077     Q_SIGNAL void closed();
0078 
0079     /**
0080      * Queue a frame to be sent to the client.
0081      *
0082      * This will add the provided frame to the queue of frames that should
0083      * be sent to the client.
0084      *
0085      * \param frame The frame to send.
0086      */
0087     void queueFrame(const VideoFrame &frame);
0088 
0089     /**
0090      * Indicate that the video state should be reset.
0091      *
0092      * This means the screen resolution and other information of the client
0093      * will be updated based on the current state of the VideoStream.
0094      */
0095     void reset();
0096 
0097     /**
0098      */
0099     bool enabled() const;
0100     void setEnabled(bool enabled);
0101     Q_SIGNAL void enabledChanged();
0102 
0103     uint32_t requestedFrameRate() const;
0104     Q_SIGNAL void requestedFrameRateChanged();
0105 
0106 private:
0107     friend BOOL gfxChannelIdAssigned(RdpgfxServerContext *, uint32_t);
0108     friend uint32_t gfxCapsAdvertise(RdpgfxServerContext *, const RDPGFX_CAPS_ADVERTISE_PDU *);
0109     friend uint32_t gfxFrameAcknowledge(RdpgfxServerContext *, const RDPGFX_FRAME_ACKNOWLEDGE_PDU *);
0110 
0111     bool onChannelIdAssigned(uint32_t channelId);
0112     uint32_t onCapsAdvertise(const RDPGFX_CAPS_ADVERTISE_PDU *capsAdvertise);
0113     uint32_t onFrameAcknowledge(const RDPGFX_FRAME_ACKNOWLEDGE_PDU *frameAcknowledge);
0114 
0115     void performReset(const QSize &size);
0116     void sendFrame(const VideoFrame &frame);
0117 
0118     void updateRequestedFrameRate();
0119 
0120     class Private;
0121     const std::unique_ptr<Private> d;
0122 };
0123 
0124 }