10#include "libvpxvp9encoder_p.h"
12#include "pipewireproduce_p.h"
18#include <libavcodec/avcodec.h>
19#include <libavfilter/buffersink.h>
20#include <libavfilter/buffersrc.h>
21#include <libavutil/pixfmt.h>
24#include "logging_record.h"
26LibVpxVp9Encoder::LibVpxVp9Encoder(PipeWireProduce *produce)
27 : SoftwareEncoder(produce)
31bool LibVpxVp9Encoder::initialize(
const QSize &size)
33 createFilterGraph(size);
35 auto codec = avcodec_find_encoder_by_name(
"libvpx-vp9");
37 qCWarning(PIPEWIRERECORD_LOGGING) <<
"libvpx-vp9 codec not found";
41 m_avCodecContext = avcodec_alloc_context3(codec);
42 if (!m_avCodecContext) {
43 qCWarning(PIPEWIRERECORD_LOGGING) <<
"Could not allocate video codec context";
48 m_avCodecContext->width = size.
width();
49 m_avCodecContext->height = size.
height();
50 m_avCodecContext->pix_fmt = AV_PIX_FMT_YUV420P;
51 m_avCodecContext->time_base = AVRational{1, 1000};
53 AVDictionary *options =
nullptr;
55 applyEncodingPreference(options);
59 const auto maxFramerate = m_produce->maxFramerate();
60 const auto fps = qreal(maxFramerate.numerator) / std::max(quint32(1), maxFramerate.denominator);
62 m_avCodecContext->gop_size = fps * 2;
66 m_avCodecContext->bit_rate = std::round(area * 2);
67 m_avCodecContext->rc_min_rate = std::round(area);
68 m_avCodecContext->rc_max_rate = std::round(area * 3);
70 m_avCodecContext->rc_buffer_size = m_avCodecContext->bit_rate;
74 if (
int result = avcodec_open2(m_avCodecContext, codec, &options); result < 0) {
75 qCWarning(PIPEWIRERECORD_LOGGING) <<
"Could not open codec" << av_err2str(result);
82int LibVpxVp9Encoder::percentageToAbsoluteQuality(
const std::optional<quint8> &quality)
88 constexpr int MinQuality = 63;
89 return std::max(1,
int(MinQuality - (m_quality.value() / 100.0) * MinQuality));
92void LibVpxVp9Encoder::applyEncodingPreference(AVDictionary *options)
95 av_dict_set(&options,
"tune-content",
"screen", 0);
100 crf = percentageToAbsoluteQuality(m_quality);
102 m_avCodecContext->qmin = std::clamp(crf / 2, 0, crf);
103 m_avCodecContext->qmax = std::clamp(qRound(crf * 1.5), crf, 63);
104 av_dict_set_int(&options,
"crf", crf, 0);
110 int cpuUsed = 5 + std::max(1,
int(3 - std::round(m_quality.value_or(50) / 100.0 * 3)));
111 av_dict_set_int(&options,
"cpu-used", cpuUsed, 0);
112 av_dict_set(&options,
"deadline",
"realtime", 0);
116 av_dict_set(&options,
"tile-columns",
"6", 0);
117 av_dict_set(&options,
"tile-rows",
"2", 0);
121 av_dict_set(&options,
"frame-parallel",
"1", 0);
bool isEmpty() const const