From 6dbe01f41565e07737dbac7e015226a5ad02e3a6 Mon Sep 17 00:00:00 2001 From: Alan Witkowski Date: Mon, 30 May 2022 13:45:25 -0600 Subject: [PATCH] preliminary AV1 support --- app/codec/exportcodec.cpp | 4 + app/codec/exportcodec.h | 1 + app/codec/exportformat.cpp | 4 +- app/codec/ffmpeg/ffmpegencoder.cpp | 2 + app/dialog/export/codec/CMakeLists.txt | 2 + app/dialog/export/codec/av1section.cpp | 132 +++++++++++++++++++++++++ app/dialog/export/codec/av1section.h | 74 ++++++++++++++ app/dialog/export/exportvideotab.cpp | 6 ++ app/dialog/export/exportvideotab.h | 2 + 9 files changed, 225 insertions(+), 2 deletions(-) create mode 100644 app/dialog/export/codec/av1section.cpp create mode 100644 app/dialog/export/codec/av1section.h diff --git a/app/codec/exportcodec.cpp b/app/codec/exportcodec.cpp index 2a908f8b5..217593d08 100644 --- a/app/codec/exportcodec.cpp +++ b/app/codec/exportcodec.cpp @@ -64,6 +64,8 @@ QString ExportCodec::GetCodecName(ExportCodec::Codec c) return tr("Vorbis"); case kCodecVP9: return tr("VP9"); + case kCodecAV1: + return tr("AV1"); case kCodecSRT: return tr("SubRip SRT"); case kCodecCount: @@ -90,6 +92,7 @@ bool ExportCodec::IsCodecAStillImage(ExportCodec::Codec c) case kCodecOpus: case kCodecFLAC: case kCodecVP9: + case kCodecAV1: case kCodecSRT: return false; case kCodecOpenEXR: @@ -121,6 +124,7 @@ bool ExportCodec::IsCodecLossless(Codec c) case kCodecVorbis: case kCodecOpus: case kCodecVP9: + case kCodecAV1: case kCodecSRT: case kCodecOpenEXR: case kCodecPNG: diff --git a/app/codec/exportcodec.h b/app/codec/exportcodec.h index 7fff8f311..c78085986 100644 --- a/app/codec/exportcodec.h +++ b/app/codec/exportcodec.h @@ -53,6 +53,7 @@ public: kCodecVorbis, kCodecFLAC, kCodecSRT, + kCodecAV1, kCodecCount }; diff --git a/app/codec/exportformat.cpp b/app/codec/exportformat.cpp index 9b6997d78..004312cbe 100644 --- a/app/codec/exportformat.cpp +++ b/app/codec/exportformat.cpp @@ -123,7 +123,7 @@ QList ExportFormat::GetVideoCodecs(ExportFormat::Format f) case kFormatQuickTime: return {ExportCodec::kCodecH264, ExportCodec::kCodecH264rgb, ExportCodec::kCodecH265, ExportCodec::kCodecProRes, ExportCodec::kCodecCineform}; case kFormatWebM: - return {ExportCodec::kCodecVP9}; + return {ExportCodec::kCodecAV1, ExportCodec::kCodecVP9}; case kFormatOgg: case kFormatWAV: case kFormatMPEG4Audio: @@ -152,7 +152,7 @@ QList ExportFormat::GetAudioCodecs(ExportFormat::Format f) case kFormatQuickTime: return {ExportCodec::kCodecAAC, ExportCodec::kCodecMP2, ExportCodec::kCodecMP3, ExportCodec::kCodecPCM}; case kFormatWebM: - return {ExportCodec::kCodecAAC, ExportCodec::kCodecMP2, ExportCodec::kCodecMP3, ExportCodec::kCodecPCM, ExportCodec::kCodecVorbis, ExportCodec::kCodecOpus}; + return {ExportCodec::kCodecOpus, ExportCodec::kCodecAAC, ExportCodec::kCodecMP2, ExportCodec::kCodecMP3, ExportCodec::kCodecPCM, ExportCodec::kCodecVorbis}; // Audio only formats case kFormatWAV: diff --git a/app/codec/ffmpeg/ffmpegencoder.cpp b/app/codec/ffmpeg/ffmpegencoder.cpp index 7980e10a7..022d1c78c 100644 --- a/app/codec/ffmpeg/ffmpegencoder.cpp +++ b/app/codec/ffmpeg/ffmpegencoder.cpp @@ -860,6 +860,8 @@ const AVCodec *FFmpegEncoder::GetEncoder(ExportCodec::Codec c, AudioParams::Form return avcodec_find_encoder(AV_CODEC_ID_HEVC); case ExportCodec::kCodecVP9: return avcodec_find_encoder(AV_CODEC_ID_VP9); + case ExportCodec::kCodecAV1: + return avcodec_find_encoder_by_name("libsvtav1"); case ExportCodec::kCodecOpenEXR: return avcodec_find_encoder(AV_CODEC_ID_EXR); case ExportCodec::kCodecPNG: diff --git a/app/dialog/export/codec/CMakeLists.txt b/app/dialog/export/codec/CMakeLists.txt index f00ce2690..d68ccd1c3 100644 --- a/app/dialog/export/codec/CMakeLists.txt +++ b/app/dialog/export/codec/CMakeLists.txt @@ -16,6 +16,8 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} + dialog/export/codec/av1section.cpp + dialog/export/codec/av1section.h dialog/export/codec/cineformsection.cpp dialog/export/codec/cineformsection.h dialog/export/codec/codecsection.cpp diff --git a/app/dialog/export/codec/av1section.cpp b/app/dialog/export/codec/av1section.cpp new file mode 100644 index 000000000..8fc5edc44 --- /dev/null +++ b/app/dialog/export/codec/av1section.cpp @@ -0,0 +1,132 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2022 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#include "av1section.h" + +#include +#include +#include +#include + +#include "common/qtutils.h" +#include "widget/slider/integerslider.h" + +namespace olive { + +AV1Section::AV1Section(QWidget *parent) : + AV1Section(AV1CRFSection::kDefaultAV1CRF, parent) +{ +} + +AV1Section::AV1Section(int default_crf, QWidget *parent) : + CodecSection(parent) +{ + QGridLayout* layout = new QGridLayout(this); + layout->setMargin(0); + + int row = 0; + layout->addWidget(new QLabel(tr("Preset:")), row, 0); + + preset_combobox_ = new QComboBox(); + preset_combobox_->setToolTip(tr("This parameter governs the efficiency/encode-time trade-off.\n" + "Lower presets will result in an output with better quality for a given file size, but will take longer to encode.\n" + "Higher presets can result in a very fast encode, but will make some compromises on visual quality for a given crf value.")); + + for (int i = 0; i <= 13; i++) + preset_combobox_->addItem(QString::number(i)); + + preset_combobox_->setCurrentIndex(8); + + layout->addWidget(preset_combobox_, row, 1); + + row++; + + layout->addWidget(new QLabel(tr("Compression Method:")), row, 0); + + QComboBox* compression_box = new QComboBox(); + compression_box->setToolTip(tr("This parameter governs the quality/size trade-off.\n" + "Higher CRF values will result in a final output that takes less space, but begins to lose detail.\n" + "Lower CRF values retain more detail at the cost of larger file sizes.\n" + "The possible range of CRF in SVT-AV1 is 1-63.")); + + // These items must correspond to the CompressionMethod enum + compression_box->addItem(tr("Constant Rate Factor")); + + layout->addWidget(compression_box, row, 1); + + row++; + + compression_method_stack_ = new QStackedWidget(); + layout->addWidget(compression_method_stack_, row, 0, 1, 2); + + crf_section_ = new AV1CRFSection(default_crf); + compression_method_stack_->addWidget(crf_section_); + + connect(compression_box, + static_cast(&QComboBox::currentIndexChanged), + compression_method_stack_, + &QStackedWidget::setCurrentIndex); +} + +void AV1Section::AddOpts(EncodingParams *params) +{ + + CompressionMethod method = static_cast(compression_method_stack_->currentIndex()); + + if (method == kConstantRateFactor) { + + // Set Quantizer value + params->set_video_option(QStringLiteral("qp"), QString::number(crf_section_->GetValue())); + + } + + params->set_video_option(QStringLiteral("preset"), QString::number(preset_combobox_->currentIndex())); +} + +AV1CRFSection::AV1CRFSection(int default_crf, QWidget *parent) : + QWidget(parent) +{ + QHBoxLayout* layout = new QHBoxLayout(this); + layout->setMargin(0); + + crf_slider_ = new QSlider(Qt::Horizontal); + crf_slider_->setMinimum(kMinimumCRF); + crf_slider_->setMaximum(kMaximumCRF); + crf_slider_->setValue(default_crf); + layout->addWidget(crf_slider_); + + IntegerSlider* crf_input = new IntegerSlider(); + crf_input->setMaximumWidth(QtUtils::QFontMetricsWidth(crf_input->fontMetrics(), QStringLiteral("HHHH"))); + crf_input->SetMinimum(kMinimumCRF); + crf_input->SetMaximum(kMaximumCRF); + crf_input->SetValue(default_crf); + crf_input->SetDefaultValue(default_crf); + layout->addWidget(crf_input); + + connect(crf_slider_, &QSlider::valueChanged, crf_input, &IntegerSlider::SetValue); + connect(crf_input, &IntegerSlider::ValueChanged, crf_slider_, &QSlider::setValue); +} + +int AV1CRFSection::GetValue() const +{ + return crf_slider_->value(); +} + +} diff --git a/app/dialog/export/codec/av1section.h b/app/dialog/export/codec/av1section.h new file mode 100644 index 000000000..065485fbc --- /dev/null +++ b/app/dialog/export/codec/av1section.h @@ -0,0 +1,74 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2022 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#ifndef AV1SECTION_H +#define AV1SECTION_H + +#include +#include +#include + +#include "codecsection.h" +#include "widget/slider/floatslider.h" + +namespace olive { + +class AV1CRFSection : public QWidget +{ + Q_OBJECT +public: + AV1CRFSection(int default_crf, QWidget* parent = nullptr); + + int GetValue() const; + + static const int kDefaultAV1CRF = 30; + +private: + static const int kMinimumCRF = 0; + static const int kMaximumCRF = 63; + + QSlider* crf_slider_; + +}; + +class AV1Section : public CodecSection +{ + Q_OBJECT +public: + enum CompressionMethod { + kConstantRateFactor, + }; + + AV1Section(QWidget* parent = nullptr); + AV1Section(int default_crf, QWidget* parent); + + virtual void AddOpts(EncodingParams* params) override; + +private: + QStackedWidget* compression_method_stack_; + + AV1CRFSection* crf_section_; + + QComboBox *preset_combobox_; +}; + +} + +#endif // AV1SECTION_H diff --git a/app/dialog/export/exportvideotab.cpp b/app/dialog/export/exportvideotab.cpp index 1c493eecf..9fe74ae7e 100644 --- a/app/dialog/export/exportvideotab.cpp +++ b/app/dialog/export/exportvideotab.cpp @@ -185,6 +185,9 @@ QWidget *ExportVideoTab::SetupCodecSection() h265_section_ = new H265Section(); codec_stack_->addWidget(h265_section_); + av1_section_ = new AV1Section(); + codec_stack_->addWidget(av1_section_); + cineform_section_ = new CineformSection(); codec_stack_->addWidget(cineform_section_); @@ -243,6 +246,9 @@ void ExportVideoTab::VideoCodecChanged() case ExportCodec::kCodecH265: SetCodecSection(h265_section_); break; + case ExportCodec::kCodecAV1: + SetCodecSection(av1_section_); + break; case ExportCodec::kCodecCineform: SetCodecSection(cineform_section_); break; diff --git a/app/dialog/export/exportvideotab.h b/app/dialog/export/exportvideotab.h index c2be1aebd..79fcb5207 100644 --- a/app/dialog/export/exportvideotab.h +++ b/app/dialog/export/exportvideotab.h @@ -26,6 +26,7 @@ #include #include "common/rational.h" +#include "dialog/export/codec/av1section.h" #include "dialog/export/codec/cineformsection.h" #include "dialog/export/codec/codecstack.h" #include "dialog/export/codec/h264section.h" @@ -161,6 +162,7 @@ private: ImageSection* image_section_; H264Section* h264_section_; H264Section* h265_section_; + AV1Section* av1_section_; CineformSection *cineform_section_; ColorSpaceChooser* color_space_chooser_;