File indexing completed on 2024-05-05 05:30:17
0001 /* 0002 SPDX-FileCopyrightText: 2022-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 #include "pipewirebaseencodedstream.h" 0008 0009 #include <logging_libav.h> 0010 #include <logging_record.h> 0011 #include <memory> 0012 #include <va/va.h> 0013 0014 extern "C" { 0015 #include <libavcodec/codec.h> 0016 #include <libavutil/log.h> 0017 } 0018 #include <unistd.h> 0019 0020 #include "pipewireproduce_p.h" 0021 #include "vaapiutils_p.h" 0022 0023 struct PipeWireEncodedStreamPrivate { 0024 uint m_nodeId = 0; 0025 std::optional<uint> m_fd; 0026 Fraction m_maxFramerate; 0027 bool m_active = false; 0028 PipeWireBaseEncodedStream::Encoder m_encoder; 0029 std::optional<quint8> m_quality; 0030 0031 std::unique_ptr<QThread> m_produceThread; 0032 std::unique_ptr<PipeWireProduce> m_produce; 0033 }; 0034 0035 PipeWireBaseEncodedStream::State PipeWireBaseEncodedStream::state() const 0036 { 0037 if (isActive()) { 0038 return Recording; 0039 } else if (d->m_produceThread && d->m_produce->m_deactivated && d->m_produceThread->isRunning()) { 0040 return Rendering; 0041 } 0042 0043 return Idle; 0044 } 0045 0046 PipeWireBaseEncodedStream::PipeWireBaseEncodedStream(QObject *parent) 0047 : QObject(parent) 0048 , d(new PipeWireEncodedStreamPrivate) 0049 { 0050 d->m_encoder = suggestedEncoders().value(0, NoEncoder); 0051 0052 const auto &category = PIPEWIRELIBAV_LOGGING(); 0053 if (category.isDebugEnabled()) { 0054 av_log_set_level(AV_LOG_DEBUG); 0055 } else if (category.isInfoEnabled()) { 0056 av_log_set_level(AV_LOG_INFO); 0057 } else if (category.isWarningEnabled()) { 0058 av_log_set_level(AV_LOG_WARNING); 0059 } else { 0060 av_log_set_level(AV_LOG_ERROR); 0061 } 0062 } 0063 0064 PipeWireBaseEncodedStream::~PipeWireBaseEncodedStream() 0065 { 0066 setActive(false); 0067 0068 if (d->m_fd) { 0069 close(*d->m_fd); 0070 } 0071 } 0072 0073 void PipeWireBaseEncodedStream::setNodeId(uint nodeId) 0074 { 0075 if (nodeId == d->m_nodeId) 0076 return; 0077 0078 d->m_nodeId = nodeId; 0079 refresh(); 0080 Q_EMIT nodeIdChanged(nodeId); 0081 } 0082 0083 void PipeWireBaseEncodedStream::setFd(uint fd) 0084 { 0085 if (fd == d->m_fd) 0086 return; 0087 0088 if (d->m_fd) { 0089 close(*d->m_fd); 0090 } 0091 d->m_fd = fd; 0092 refresh(); 0093 Q_EMIT fdChanged(fd); 0094 } 0095 0096 Fraction PipeWireBaseEncodedStream::maxFramerate() const 0097 { 0098 if (d->m_maxFramerate) { 0099 return d->m_maxFramerate; 0100 } 0101 return Fraction{60, 1}; 0102 } 0103 0104 void PipeWireBaseEncodedStream::setMaxFramerate(const Fraction &framerate) 0105 { 0106 if (d->m_maxFramerate == framerate) { 0107 return; 0108 } 0109 d->m_maxFramerate = framerate; 0110 Q_EMIT maxFramerateChanged(); 0111 } 0112 0113 void PipeWireBaseEncodedStream::setMaxFramerate(quint32 numerator, quint32 denominator) 0114 { 0115 setMaxFramerate({numerator, denominator}); 0116 } 0117 0118 void PipeWireBaseEncodedStream::setActive(bool active) 0119 { 0120 if (d->m_active == active) 0121 return; 0122 0123 d->m_active = active; 0124 refresh(); 0125 Q_EMIT activeChanged(active); 0126 } 0127 0128 std::optional<quint8> PipeWireBaseEncodedStream::quality() const 0129 { 0130 return d->m_quality; 0131 } 0132 0133 void PipeWireBaseEncodedStream::setQuality(quint8 quality) 0134 { 0135 d->m_quality = quality; 0136 if (d->m_produce) { 0137 d->m_produce->setQuality(d->m_quality); 0138 } 0139 } 0140 0141 void PipeWireBaseEncodedStream::refresh() 0142 { 0143 if (d->m_produceThread) { 0144 QMetaObject::invokeMethod(d->m_produce.get(), &PipeWireProduce::deactivate, Qt::QueuedConnection); 0145 d->m_produceThread->wait(); 0146 0147 d->m_produce.reset(); 0148 d->m_produceThread.reset(); 0149 } 0150 0151 if (d->m_active && d->m_nodeId > 0) { 0152 d->m_produceThread = std::make_unique<QThread>(); 0153 d->m_produceThread->setObjectName("PipeWireProduce::input"); 0154 d->m_produce = makeProduce(); 0155 d->m_produce->setQuality(d->m_quality); 0156 d->m_produce->moveToThread(d->m_produceThread.get()); 0157 d->m_produceThread->start(); 0158 QMetaObject::invokeMethod(d->m_produce.get(), &PipeWireProduce::initialize, Qt::QueuedConnection); 0159 } 0160 0161 Q_EMIT stateChanged(); 0162 } 0163 0164 void PipeWireBaseEncodedStream::setEncoder(Encoder encoder) 0165 { 0166 if (d->m_encoder == encoder || !suggestedEncoders().contains(encoder)) { 0167 return; 0168 } 0169 d->m_encoder = encoder; 0170 Q_EMIT encoderChanged(); 0171 } 0172 0173 PipeWireBaseEncodedStream::Encoder PipeWireBaseEncodedStream::encoder() const 0174 { 0175 return d->m_encoder; 0176 } 0177 0178 QList<PipeWireBaseEncodedStream::Encoder> PipeWireBaseEncodedStream::suggestedEncoders() const 0179 { 0180 VaapiUtils vaapi; 0181 0182 QList<PipeWireBaseEncodedStream::Encoder> ret = {PipeWireBaseEncodedStream::VP8, 0183 PipeWireBaseEncodedStream::VP9, 0184 PipeWireBaseEncodedStream::H264Main, 0185 PipeWireBaseEncodedStream::H264Baseline}; 0186 auto removeUnavailableEncoders = [&vaapi](const PipeWireBaseEncodedStream::Encoder &encoder) { 0187 switch (encoder) { 0188 case PipeWireBaseEncodedStream::VP8: 0189 if (vaapi.supportsProfile(VAProfileVP8Version0_3) && avcodec_find_encoder_by_name("vp8_vaapi")) { 0190 return false; 0191 } else { 0192 return !avcodec_find_encoder_by_name("libvpx"); 0193 } 0194 case PipeWireBaseEncodedStream::VP9: 0195 return !avcodec_find_encoder_by_name("libvpx-vp9"); 0196 case PipeWireBaseEncodedStream::H264Main: 0197 case PipeWireBaseEncodedStream::H264Baseline: 0198 if (vaapi.supportsProfile(encoder == PipeWireBaseEncodedStream::H264Main ? VAProfileH264Main : VAProfileH264ConstrainedBaseline) 0199 && avcodec_find_encoder_by_name("h264_vaapi")) { 0200 return false; 0201 } else { 0202 return !avcodec_find_encoder_by_name("libx264"); 0203 } 0204 default: 0205 return true; 0206 } 0207 }; 0208 ret.removeIf(removeUnavailableEncoders); 0209 return ret; 0210 } 0211 0212 bool PipeWireBaseEncodedStream::isActive() const 0213 { 0214 return d->m_active; 0215 } 0216 0217 uint PipeWireBaseEncodedStream::nodeId() const 0218 { 0219 return d->m_nodeId; 0220 } 0221 0222 uint PipeWireBaseEncodedStream::fd() const 0223 { 0224 return d->m_fd.value_or(0); 0225 } 0226 0227 #include "moc_pipewirebaseencodedstream.cpp"