File indexing completed on 2024-05-05 05:30:17
0001 /* 0002 SPDX-FileCopyrightText: 2023 Aleix Pol Gonzalez <aleixpol@kde.org> 0003 SPDX-FileCopyrightText: 2023 Marco Martin <mart@kde.org> 0004 SPDX-FileCopyrightText: 2023 Arjen Hiemstra <ahiemstra@heimr.nl> 0005 0006 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0007 */ 0008 0009 #pragma once 0010 0011 #include <mutex> 0012 0013 #include <QObject> 0014 0015 #include "dmabufhandler.h" 0016 0017 extern "C" { 0018 #include "libavcodec/avcodec.h" 0019 #include "libavfilter/avfilter.h" 0020 } 0021 0022 #undef av_err2str 0023 // The one provided by libav fails to compile on GCC due to passing data from the function scope outside 0024 char *av_err2str(int errnum); 0025 0026 struct PipeWireFrame; 0027 class PipeWireProduce; 0028 0029 /** 0030 * Base class for objects that encapsulate encoder logic and state. 0031 */ 0032 class Encoder : public QObject 0033 { 0034 Q_OBJECT 0035 public: 0036 enum class H264Profile { Baseline, Main, High }; 0037 0038 /** 0039 * Constructor. 0040 * 0041 * @param produce The PipeWireProduce instance that owns this encoder. 0042 */ 0043 Encoder(PipeWireProduce *produce); 0044 ~Encoder() override; 0045 0046 /** 0047 * Initialize and setup the encoder. 0048 * 0049 * @param size The size of the stream being encoded. 0050 * 0051 * @return true if initailization was succesful, false if not. 0052 */ 0053 virtual bool initialize(const QSize &size) = 0; 0054 /** 0055 * Process a PipeWire frame and pass it to libav for filtering. 0056 * 0057 * @param frame The frame to process. 0058 * 0059 * @note This method will be called on its own thread. 0060 */ 0061 virtual void filterFrame(const PipeWireFrame &frame) = 0; 0062 /** 0063 * Get the next finished frames from the libav filter chain and queue them for encoding. 0064 * 0065 * @param maximumFrames The maximum number of frames that can be queued for encoding. 0066 * 0067 * @return A pair with the number of frames removed from the filter chain as first entry 0068 * and the number of frames queued for encoding as the second entry. 0069 * 0070 * @note This method will be called on its own thread. 0071 */ 0072 virtual std::pair<int, int> encodeFrame(int maximumFrames); 0073 /** 0074 * Get the next encoded frames from libav and pass them to PipeWireProduce. 0075 * 0076 * @return The number of encoded frames that were received. 0077 * 0078 * @note This method will be called on its own thread. 0079 */ 0080 virtual int receivePacket(); 0081 /** 0082 * End encoding and perform any necessary cleanup. 0083 */ 0084 virtual void finish(); 0085 0086 /** 0087 * Return the AVCodecContext for this encoder. 0088 */ 0089 AVCodecContext *avCodecContext() const; 0090 0091 /** 0092 * Set the quality level, from 0 (lowest) to 100 (highest). 0093 * 0094 * Internally this will be converted to an encoder-specific quality value. 0095 */ 0096 void setQuality(std::optional<quint8> quality); 0097 0098 protected: 0099 virtual int percentageToAbsoluteQuality(const std::optional<quint8> &quality) = 0; 0100 0101 PipeWireProduce *m_produce; 0102 0103 AVCodecContext *m_avCodecContext = nullptr; 0104 std::mutex m_avCodecMutex; 0105 0106 AVFilterGraph *m_avFilterGraph = nullptr; 0107 AVFilterContext *m_inputFilter = nullptr; 0108 AVFilterContext *m_outputFilter = nullptr; 0109 0110 std::optional<quint8> m_quality; 0111 }; 0112 0113 /** 0114 * Encoder subclass that can be used as base class for software encoders. 0115 */ 0116 class SoftwareEncoder : public Encoder 0117 { 0118 public: 0119 SoftwareEncoder(PipeWireProduce *produce); 0120 0121 void filterFrame(const PipeWireFrame &frame) override; 0122 0123 protected: 0124 /** 0125 * Create a default filter graph that converts from RGBA to YUV420P. 0126 * 0127 * @param size The size of the stream to encode. 0128 */ 0129 bool createFilterGraph(const QSize &size); 0130 0131 DmaBufHandler m_dmaBufHandler; 0132 }; 0133 0134 /** 0135 * Encoder subclass that can be used as base class for hardware encoders. 0136 */ 0137 class HardwareEncoder : public Encoder 0138 { 0139 public: 0140 HardwareEncoder(PipeWireProduce *produce); 0141 ~HardwareEncoder() override; 0142 0143 void filterFrame(const PipeWireFrame &frame) override; 0144 0145 protected: 0146 /** 0147 * Check if VAAPI is supported for a given size stream. 0148 * 0149 * @param size The size of the stream to check. 0150 * 0151 * @return The path to a device node that can encode this stream. If 0152 * the stream cannot be encoded by the current hardware, an 0153 * empty QByteArray will be returned. 0154 */ 0155 QByteArray checkVaapi(const QSize &size); 0156 /** 0157 * Create the libav contexts for the DRM subsystem. 0158 * 0159 * These contexts are used when doing import of dma-buf based frames. 0160 * 0161 * @param path The path to a device node where the frames are. 0162 * @param size The size of the frames. 0163 * 0164 * @return true if the contexts were successfully created, false if not. 0165 */ 0166 bool createDrmContext(const QSize &size); 0167 0168 AVBufferRef *m_drmContext = nullptr; 0169 AVBufferRef *m_drmFramesContext = nullptr; 0170 0171 private: 0172 bool m_supportsHardwareModifiers; 0173 };