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 #include "libvpxencoder_p.h" 0010 0011 #include <QSize> 0012 #include <QThread> 0013 0014 extern "C" { 0015 #include <libavcodec/avcodec.h> 0016 #include <libavfilter/buffersink.h> 0017 #include <libavfilter/buffersrc.h> 0018 #include <libavutil/pixfmt.h> 0019 } 0020 0021 #include "logging_record.h" 0022 0023 LibVpxEncoder::LibVpxEncoder(PipeWireProduce *produce) 0024 : SoftwareEncoder(produce) 0025 { 0026 } 0027 0028 bool LibVpxEncoder::initialize(const QSize &size) 0029 { 0030 createFilterGraph(size); 0031 0032 auto codec = avcodec_find_encoder_by_name("libvpx"); 0033 if (!codec) { 0034 qCWarning(PIPEWIRERECORD_LOGGING) << "libvpx codec not found"; 0035 return false; 0036 } 0037 0038 m_avCodecContext = avcodec_alloc_context3(codec); 0039 if (!m_avCodecContext) { 0040 qCWarning(PIPEWIRERECORD_LOGGING) << "Could not allocate video codec context"; 0041 return false; 0042 } 0043 m_avCodecContext->bit_rate = size.width() * size.height() * 2; 0044 0045 Q_ASSERT(!size.isEmpty()); 0046 m_avCodecContext->width = size.width(); 0047 m_avCodecContext->height = size.height(); 0048 m_avCodecContext->max_b_frames = 0; 0049 m_avCodecContext->gop_size = 100; 0050 m_avCodecContext->pix_fmt = AV_PIX_FMT_YUV420P; 0051 m_avCodecContext->time_base = AVRational{1, 1000}; 0052 m_avCodecContext->global_quality = 35; 0053 0054 if (m_quality) { 0055 m_avCodecContext->global_quality = percentageToAbsoluteQuality(m_quality); 0056 } else { 0057 m_avCodecContext->global_quality = 35; 0058 } 0059 0060 AVDictionary *options = nullptr; 0061 av_dict_set_int(&options, "threads", qMin(16, QThread::idealThreadCount()), 0); 0062 av_dict_set(&options, "preset", "veryfast", 0); 0063 av_dict_set(&options, "tune-content", "screen", 0); 0064 av_dict_set(&options, "deadline", "realtime", 0); 0065 // In theory a lower number should be faster, but the opposite seems to be true 0066 // av_dict_set(&options, "quality", "40", 0); 0067 // Disable motion estimation, not great while dragging windows but speeds up encoding by an order of magnitude 0068 av_dict_set(&options, "flags", "+mv4", 0); 0069 // Disable in-loop filtering 0070 av_dict_set(&options, "-flags", "+loop", 0); 0071 av_dict_set(&options, "crf", "45", 0); 0072 0073 if (int result = avcodec_open2(m_avCodecContext, codec, &options); result < 0) { 0074 qCWarning(PIPEWIRERECORD_LOGGING) << "Could not open codec" << av_err2str(result); 0075 return false; 0076 } 0077 0078 return true; 0079 } 0080 0081 int LibVpxEncoder::percentageToAbsoluteQuality(const std::optional<quint8> &quality) 0082 { 0083 if (!quality) { 0084 return -1; 0085 } 0086 0087 constexpr int MinQuality = 63; 0088 return std::max(1, int(MinQuality - (m_quality.value() / 100.0) * MinQuality)); 0089 }