File indexing completed on 2024-05-05 05:30:18
0001 /* 0002 SPDX-FileCopyrightText: 2023 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 <QObject> 0010 #include <epoxy/egl.h> 0011 0012 extern "C" { 0013 #include <pipewire/pipewire.h> 0014 #include <spa/param/format-utils.h> 0015 #include <spa/param/props.h> 0016 #include <spa/param/video/format-utils.h> 0017 } 0018 0019 #include <QFile> 0020 #include <QImage> 0021 #include <QMutex> 0022 #include <QPoint> 0023 #include <QQueue> 0024 #include <QRunnable> 0025 #include <QThread> 0026 #include <QWaitCondition> 0027 0028 #include <condition_variable> 0029 #include <functional> 0030 #include <mutex> 0031 #include <optional> 0032 #include <thread> 0033 0034 #include "pipewirebaseencodedstream.h" 0035 #include "pipewiresourcestream.h" 0036 0037 struct AVCodec; 0038 struct AVCodecContext; 0039 struct AVFrame; 0040 struct AVPacket; 0041 0042 struct AVFilterContext; 0043 struct AVFilterGraph; 0044 0045 class CustomAVFrame; 0046 class Encoder; 0047 class PipeWireReceiveEncodedThread; 0048 0049 class PipeWireProduce : public QObject 0050 { 0051 Q_OBJECT 0052 public: 0053 PipeWireProduce(PipeWireBaseEncodedStream::Encoder encoderType, uint nodeId, uint fd, const Fraction &framerate); 0054 ~PipeWireProduce() override; 0055 0056 virtual void initialize(); 0057 0058 QString error() const 0059 { 0060 return m_error; 0061 } 0062 0063 Fraction maxFramerate() const; 0064 void setMaxFramerate(const Fraction &framerate); 0065 0066 virtual int64_t framePts(const std::optional<std::chrono::nanoseconds> &presentationTimestamp) 0067 { 0068 return std::chrono::duration_cast<std::chrono::milliseconds>(presentationTimestamp.value()).count(); 0069 } 0070 0071 virtual void processPacket(AVPacket *packet) = 0; 0072 virtual bool setupFormat() 0073 { 0074 return true; 0075 } 0076 virtual void cleanup() 0077 { 0078 } 0079 0080 void stateChanged(pw_stream_state state); 0081 friend class PipeWireProduceThread; 0082 void setupStream(); 0083 virtual void processFrame(const PipeWireFrame &frame); 0084 void render(const QImage &image, const PipeWireFrame &frame); 0085 virtual void aboutToEncode(PipeWireFrame &frame) 0086 { 0087 Q_UNUSED(frame); 0088 } 0089 0090 void deactivate(); 0091 0092 void setQuality(const std::optional<quint8> &quality); 0093 0094 const uint m_nodeId; 0095 QScopedPointer<PipeWireSourceStream> m_stream; 0096 QString m_error; 0097 0098 PipeWireBaseEncodedStream::Encoder m_encoderType; 0099 QByteArray m_encoderName; 0100 std::unique_ptr<Encoder> m_encoder; 0101 0102 uint m_fd; 0103 Fraction m_frameRate; 0104 0105 std::optional<quint8> m_quality; 0106 0107 struct { 0108 QImage texture; 0109 std::optional<QPoint> position; 0110 QPoint hotspot; 0111 bool dirty = false; 0112 } m_cursor; 0113 0114 std::thread m_passthroughThread; 0115 std::thread m_outputThread; 0116 // Can't use jthread directly as it's not available in libc++ yet, 0117 // so manually handle the stop source. 0118 std::atomic_bool m_passthroughRunning = false; 0119 std::atomic_bool m_outputRunning = false; 0120 0121 std::condition_variable m_frameReceivedCondition; 0122 std::mutex m_frameReceivedMutex; 0123 0124 std::atomic_bool m_deactivated = false; 0125 0126 int64_t m_previousPts = -1; 0127 0128 std::atomic_int m_pendingFilterFrames = 0; 0129 std::atomic_int m_pendingEncodeFrames = 0; 0130 0131 Q_SIGNALS: 0132 void producedFrames(); 0133 0134 private: 0135 void initFiltersVaapi(); 0136 void initFiltersSoftware(); 0137 std::unique_ptr<Encoder> makeEncoder(); 0138 };