7#include "pipewirebaseencodedstream.h"
9#include <logging_libav.h>
10#include <logging_record.h>
15#include <libavcodec/codec.h>
16#include <libavutil/log.h>
22#include "pipewireproduce_p.h"
23#include "vaapiutils_p.h"
25struct PipeWireEncodedStreamPrivate {
27 std::optional<uint> m_fd;
28 Fraction m_maxFramerate;
29 int m_maxPendingFrames = 50;
30 bool m_active =
false;
31 PipeWireBaseEncodedStream::Encoder m_encoder = PipeWireBaseEncodedStream::NoEncoder;
32 std::optional<quint8> m_quality;
33 PipeWireBaseEncodedStream::EncodingPreference m_encodingPreference;
34 PipeWireBaseEncodedStream::State m_state = PipeWireBaseEncodedStream::Idle;
36 std::unique_ptr<QThread> m_produceThread;
37 std::unique_ptr<PipeWireProduce> m_produce;
40PipeWireBaseEncodedStream::State PipeWireBaseEncodedStream::state()
const
45PipeWireBaseEncodedStream::PipeWireBaseEncodedStream(
QObject *parent)
47 , d(new PipeWireEncodedStreamPrivate)
49 const auto &
category = PIPEWIRELIBAV_LOGGING();
51 av_log_set_level(AV_LOG_DEBUG);
52 }
else if (
category.isInfoEnabled()) {
53 av_log_set_level(AV_LOG_INFO);
54 }
else if (
category.isWarningEnabled()) {
55 av_log_set_level(AV_LOG_WARNING);
57 av_log_set_level(AV_LOG_ERROR);
61PipeWireBaseEncodedStream::~PipeWireBaseEncodedStream()
65 if (d->m_produceThread) {
66 d->m_produceThread->wait();
70void PipeWireBaseEncodedStream::setNodeId(uint nodeId)
72 if (nodeId == d->m_nodeId)
76 Q_EMIT nodeIdChanged(nodeId);
79void PipeWireBaseEncodedStream::setFd(uint fd)
91Fraction PipeWireBaseEncodedStream::maxFramerate()
const
93 if (d->m_maxFramerate) {
94 return d->m_maxFramerate;
96 return Fraction{60, 1};
99void PipeWireBaseEncodedStream::setMaxFramerate(
const Fraction &framerate)
101 if (d->m_maxFramerate == framerate) {
104 d->m_maxFramerate = framerate;
107 d->m_produce->setMaxFramerate(d->m_maxFramerate);
110 Q_EMIT maxFramerateChanged();
113void PipeWireBaseEncodedStream::setMaxFramerate(quint32 numerator, quint32 denominator)
115 setMaxFramerate({numerator, denominator});
118void PipeWireBaseEncodedStream::setMaxPendingFrames(
int maxPendingFrames)
120 if (d->m_maxPendingFrames == maxPendingFrames) {
124 d->m_produce->setMaxPendingFrames(maxPendingFrames);
126 d->m_maxPendingFrames = maxPendingFrames;
127 Q_EMIT maxPendingFramesChanged();
130int PipeWireBaseEncodedStream::maxBufferSize()
const
132 return d->m_maxPendingFrames;
135void PipeWireBaseEncodedStream::setActive(
bool active)
142 if (d->m_produceThread) {
143 d->m_produceThread->wait();
148void PipeWireBaseEncodedStream::start()
150 if (d->m_nodeId == 0) {
151 qCWarning(PIPEWIRERECORD_LOGGING) <<
"Cannot start recording on a stream without a node ID";
155 if (d->m_produceThread || d->m_state != Idle) {
159 if (d->m_encoder == PipeWireBaseEncodedStream::NoEncoder) {
160 d->m_encoder = suggestedEncoders().value(0, NoEncoder);
163 d->m_produceThread = std::make_unique<QThread>();
164 d->m_produceThread->setObjectName(
"PipeWireProduce::input");
165 d->m_produce = makeProduce();
166 d->m_produce->setQuality(d->m_quality);
167 d->m_produce->setMaxPendingFrames(d->m_maxPendingFrames);
168 d->m_produce->setEncodingPreference(d->m_encodingPreference);
169 d->m_produce->moveToThread(d->m_produceThread.get());
170 d->m_produceThread->start();
173 connect(d->m_produce.get(), &PipeWireProduce::started,
this, [
this]() {
175 Q_EMIT activeChanged(true);
176 d->m_state = Recording;
177 Q_EMIT stateChanged();
180 connect(d->m_produce.get(), &PipeWireProduce::finished,
this, [
this]() {
182 Q_EMIT activeChanged(false);
184 Q_EMIT stateChanged();
188 d->m_produce.reset();
189 d->m_produceThread.reset();
193 close(d->m_fd.value());
198void PipeWireBaseEncodedStream::stop()
200 if (d->m_produceThread) {
204 d->m_state = PipeWireBaseEncodedStream::Rendering;
208std::optional<quint8> PipeWireBaseEncodedStream::quality()
const
213void PipeWireBaseEncodedStream::setQuality(quint8 quality)
215 d->m_quality = quality;
217 d->m_produce->setQuality(d->m_quality);
221void PipeWireBaseEncodedStream::setEncoder(Encoder encoder)
223 if (d->m_encoder == encoder || !suggestedEncoders().contains(encoder)) {
226 d->m_encoder = encoder;
230PipeWireBaseEncodedStream::Encoder PipeWireBaseEncodedStream::encoder()
const
237 auto vaapi = VaapiUtils::instance();
239 QList<PipeWireBaseEncodedStream::Encoder> ret = {PipeWireBaseEncodedStream::VP8,
240 PipeWireBaseEncodedStream::VP9,
241 PipeWireBaseEncodedStream::H264Main,
242 PipeWireBaseEncodedStream::H264Baseline,
243 PipeWireBaseEncodedStream::WebP,
244 PipeWireBaseEncodedStream::Gif,
246 auto removeUnavailableEncoders = [&vaapi](
const PipeWireBaseEncodedStream::Encoder &encoder) {
248 case PipeWireBaseEncodedStream::VP8:
249 if (vaapi->supportsProfile(VAProfileVP8Version0_3) && avcodec_find_encoder_by_name(
"vp8_vaapi")) {
252 return !avcodec_find_encoder_by_name(
"libvpx");
254 case PipeWireBaseEncodedStream::VP9:
255 return !avcodec_find_encoder_by_name(
"libvpx-vp9");
256 case PipeWireBaseEncodedStream::H264Main:
257 case PipeWireBaseEncodedStream::H264Baseline:
258 if (vaapi->supportsProfile(encoder == PipeWireBaseEncodedStream::H264Main ? VAProfileH264Main : VAProfileH264ConstrainedBaseline)
259 && avcodec_find_encoder_by_name(
"h264_vaapi")) {
262 return !(avcodec_find_encoder_by_name(
"libx264") || avcodec_find_encoder_by_name(
"libopenh264"));
264 case PipeWireBaseEncodedStream::WebP:
265 return !avcodec_find_encoder_by_name(
"libwebp");
266 case PipeWireBaseEncodedStream::Gif:
267 return !avcodec_find_encoder_by_name(
"gif");
272 ret.
removeIf(removeUnavailableEncoders);
276void PipeWireBaseEncodedStream::setEncodingPreference(PipeWireBaseEncodedStream::EncodingPreference preference)
278 d->m_encodingPreference = preference;
280 d->m_produce->setEncodingPreference(d->m_encodingPreference);
284PipeWireBaseEncodedStream::EncodingPreference PipeWireBaseEncodedStream::encodingPreference()
286 return d->m_encodingPreference;
289bool PipeWireBaseEncodedStream::isActive()
const
294uint PipeWireBaseEncodedStream::nodeId()
const
299uint PipeWireBaseEncodedStream::fd()
const
301 return d->m_fd.value_or(0);
304#include "moc_pipewirebaseencodedstream.cpp"
const QList< QKeySequence > & close()
Category category(StandardShortcut id)
qsizetype removeIf(Predicate pred)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)