KPipewire

libvpxencoder.cpp
1/*
2 SPDX-FileCopyrightText: 2023 Aleix Pol Gonzalez <aleixpol@kde.org>
3 SPDX-FileCopyrightText: 2023 Marco Martin <mart@kde.org>
4 SPDX-FileCopyrightText: 2023 Arjen Hiemstra <ahiemstra@heimr.nl>
5
6 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7*/
8
9#include "libvpxencoder_p.h"
10
11#include <QSize>
12#include <QThread>
13
14extern "C" {
15#include <libavcodec/avcodec.h>
16#include <libavfilter/buffersink.h>
17#include <libavfilter/buffersrc.h>
18#include <libavutil/pixfmt.h>
19}
20
21#include "logging_record.h"
22
23LibVpxEncoder::LibVpxEncoder(PipeWireProduce *produce)
24 : SoftwareEncoder(produce)
25{
26}
27
28bool LibVpxEncoder::initialize(const QSize &size)
29{
30 createFilterGraph(size);
31
32 auto codec = avcodec_find_encoder_by_name("libvpx");
33 if (!codec) {
34 qCWarning(PIPEWIRERECORD_LOGGING) << "libvpx codec not found";
35 return false;
36 }
37
38 m_avCodecContext = avcodec_alloc_context3(codec);
39 if (!m_avCodecContext) {
40 qCWarning(PIPEWIRERECORD_LOGGING) << "Could not allocate video codec context";
41 return false;
42 }
43 m_avCodecContext->bit_rate = size.width() * size.height() * 2;
44
45 Q_ASSERT(!size.isEmpty());
46 m_avCodecContext->width = size.width();
47 m_avCodecContext->height = size.height();
48 m_avCodecContext->max_b_frames = 0;
49 m_avCodecContext->gop_size = 100;
50 m_avCodecContext->pix_fmt = AV_PIX_FMT_YUV420P;
51 m_avCodecContext->time_base = AVRational{1, 1000};
52 m_avCodecContext->global_quality = 35;
53
54 if (m_quality) {
55 m_avCodecContext->global_quality = percentageToAbsoluteQuality(m_quality);
56 } else {
57 m_avCodecContext->global_quality = 35;
58 }
59
60 AVDictionary *options = nullptr;
61 applyEncodingPreference(options);
62
63 if (int result = avcodec_open2(m_avCodecContext, codec, &options); result < 0) {
64 qCWarning(PIPEWIRERECORD_LOGGING) << "Could not open codec" << av_err2str(result);
65 return false;
66 }
67
68 return true;
69}
70
71int LibVpxEncoder::percentageToAbsoluteQuality(const std::optional<quint8> &quality)
72{
73 if (!quality) {
74 return -1;
75 }
76
77 constexpr int MinQuality = 63;
78 return std::max(1, int(MinQuality - (m_quality.value() / 100.0) * MinQuality));
79}
80
81void LibVpxEncoder::applyEncodingPreference(AVDictionary *options)
82{
83 av_dict_set_int(&options, "threads", qMin(16, QThread::idealThreadCount()), 0);
84 av_dict_set(&options, "preset", "veryfast", 0);
85 av_dict_set(&options, "tune-content", "screen", 0);
86 av_dict_set(&options, "deadline", "realtime", 0);
87 // In theory a lower number should be faster, but the opposite seems to be true
88 // av_dict_set(&options, "quality", "40", 0);
89 // Disable motion estimation, not great while dragging windows but speeds up encoding by an order of magnitude
90 av_dict_set(&options, "flags", "+mv4", 0);
91 // Disable in-loop filtering
92 av_dict_set(&options, "-flags", "+loop", 0);
93 av_dict_set(&options, "crf", "45", 0);
94}
int height() const const
bool isEmpty() const const
int width() const const
int idealThreadCount()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 17:05:20 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.