File indexing completed on 2024-03-24 17:02:23
0001 /* 0002 SPDX-FileCopyrightText: 2022 Aleix Pol Gonzalez <aleixpol@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #pragma once 0008 0009 #include <QFile> 0010 #include <QImage> 0011 #include <QPoint> 0012 #include <QRunnable> 0013 #include <QThread> 0014 #include <QWaitCondition> 0015 0016 #include <functional> 0017 #include <optional> 0018 0019 #include <epoxy/egl.h> 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 "dmabufhandler.h" 0026 #include "pipewiresourcestream.h" 0027 0028 struct AVCodec; 0029 struct AVCodecContext; 0030 struct AVFrame; 0031 struct AVFormatContext; 0032 struct AVPacket; 0033 class CustomAVFrame; 0034 class PipeWireRecordProduce; 0035 struct gbm_device; 0036 0037 class PipeWireRecordWrite : public QObject 0038 { 0039 public: 0040 PipeWireRecordWrite(PipeWireRecordProduce *produce, AVFormatContext *avFormatContext, AVCodecContext *avCodecContext); 0041 ~PipeWireRecordWrite(); 0042 0043 void addFrame(const QImage &image, std::optional<int> sequential, std::optional<std::chrono::nanoseconds> presentationTimestamp); 0044 0045 private: 0046 QAtomicInt m_active = true; 0047 AVPacket *m_packet; 0048 AVFormatContext *const m_avFormatContext; 0049 AVCodecContext *const m_avCodecContext; 0050 struct SwsContext *sws_context = nullptr; 0051 int64_t m_lastPts = -1; 0052 uint m_lastKeyFrame = 0; 0053 QSize m_lastReceivedSize; 0054 }; 0055 0056 class PipeWireRecordWriteThread : public QThread 0057 { 0058 public: 0059 PipeWireRecordWriteThread(PipeWireRecordProduce *produce, AVFormatContext *avFormatContext, AVCodecContext *avCodecContext); 0060 0061 void run() override; 0062 void drain(); 0063 0064 private: 0065 PipeWireRecordProduce *const m_produce; 0066 AVFormatContext *const m_avFormatContext; 0067 AVCodecContext *const m_avCodecContext; 0068 }; 0069 0070 class PipeWireRecordProduce : public QObject 0071 { 0072 Q_OBJECT 0073 public: 0074 PipeWireRecordProduce(const QByteArray &encoder, uint nodeId, uint fd, const QString &output); 0075 ~PipeWireRecordProduce() override; 0076 0077 QString error() const 0078 { 0079 return m_error; 0080 } 0081 0082 Q_SIGNALS: 0083 void producedFrame(const QImage &image, std::optional<int> sequential, std::optional<std::chrono::nanoseconds> presentationTimestamp); 0084 0085 private: 0086 friend class PipeWireRecordProduceThread; 0087 void setupStream(); 0088 void processFrame(const PipeWireFrame &frame); 0089 void updateTextureImage(const QImage &image, const PipeWireFrame &frame); 0090 void render(const PipeWireFrame &frame); 0091 void stateChanged(pw_stream_state state); 0092 0093 AVCodecContext *m_avCodecContext = nullptr; 0094 const AVCodec *m_codec = nullptr; 0095 AVFormatContext *m_avFormatContext = nullptr; 0096 const QString m_output; 0097 const uint m_nodeId; 0098 QScopedPointer<PipeWireSourceStream> m_stream; 0099 QString m_error; 0100 0101 PipeWireRecordWriteThread *m_writeThread = nullptr; 0102 const QByteArray m_encoder; 0103 0104 struct { 0105 QImage texture; 0106 std::optional<QPoint> position; 0107 QPoint hotspot; 0108 bool dirty = false; 0109 } m_cursor; 0110 QImage m_frameWithoutMetadataCursor; 0111 DmaBufHandler m_dmabufHandler; 0112 QAtomicInt m_deactivated = false; 0113 }; 0114 0115 class PipeWireRecordProduceThread : public QThread 0116 { 0117 Q_OBJECT 0118 public: 0119 PipeWireRecordProduceThread(const QByteArray &encoder, uint nodeId, uint fd, const QString &output) 0120 : m_nodeId(nodeId) 0121 , m_fd(fd) 0122 , m_output(output) 0123 , m_encoder(encoder) 0124 { 0125 } 0126 void run() override; 0127 void deactivate(); 0128 0129 Q_SIGNALS: 0130 void errorFound(const QString &error); 0131 0132 private: 0133 const uint m_nodeId; 0134 const uint m_fd; 0135 const QString m_output; 0136 PipeWireRecordProduce *m_producer = nullptr; 0137 const QByteArray m_encoder; 0138 }; 0139 0140 struct PipeWireRecordPrivate { 0141 uint m_nodeId = 0; 0142 std::optional<uint> m_fd; 0143 bool m_active = false; 0144 QString m_output; 0145 std::unique_ptr<PipeWireRecordProduceThread> m_recordThread; 0146 bool m_produceThreadFinished = true; 0147 QByteArray m_encoder; 0148 };