Skip to content

Commit

Permalink
Render: support video codec profiles
Browse files Browse the repository at this point in the history
Adds support for video codec profile:

- H264 (baseline/main/high)
- ProRes (proxy/lt/standard/hq/4444/xq)
- AV1 (main/high/professional)
- VP9 (0/1/2/3)
- MPEG4 (simple/core/main)
- VC1 (simple/main(complex/advanced)

WARNING! This commit bumps the evformat. Project files saved with this commit or later will not be compatible with earlier versions of Friction (or enve).

This commit needs more testing before merged into main.

Ref: #129
  • Loading branch information
rodlie committed Mar 30, 2024
1 parent 4a3d1a9 commit 29ae228
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 3 deletions.
62 changes: 60 additions & 2 deletions src/app/GUI/RenderWidgets/outputsettingsdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,13 @@ OutputSettingsDialog::OutputSettingsDialog(const OutputSettings &settings,
mBitrateSpinBox->setRange(0.1, 100.);
mBitrateSpinBox->setSuffix(" Mbps");

mVideoProfileLabel = new QLabel(tr("Profile"), this);
mVideoProfileComboBox = new QComboBox(this);

mVideoSettingsLayout->addPair(mVideoCodecsLabel,
mVideoCodecsComboBox);
mVideoSettingsLayout->addPair(mVideoProfileLabel,
mVideoProfileComboBox);
mVideoSettingsLayout->addPair(mPixelFormatsLabel,
mPixelFormatsComboBox);
mVideoSettingsLayout->addPair(mBitrateLabel,
Expand Down Expand Up @@ -161,8 +166,10 @@ OutputSettingsDialog::OutputSettingsDialog(const OutputSettings &settings,
eSizesUI::widget.addSpacing(mMainLayout);
mMainLayout->addLayout(mButtonsLayout);

connect(mVideoCodecsComboBox, &QComboBox::currentTextChanged,
this, &OutputSettingsDialog::updateAvailablePixelFormats);
connect(mVideoCodecsComboBox, &QComboBox::currentTextChanged, [this]() {
updateAvailablePixelFormats();
updateAvailableVideoProfiles();
});

connect(mAudioCodecsComboBox, &QComboBox::currentTextChanged, [this]() {
updateAvailableSampleFormats();
Expand Down Expand Up @@ -200,6 +207,7 @@ OutputSettings OutputSettingsDialog::getSettings() {
}
settings.fVideoPixelFormat = currentPixelFormat;
settings.fVideoBitrate = qRound(mBitrateSpinBox->value()*1000000);
settings.fVideoProfile = mVideoProfileComboBox->currentData().toInt();

settings.fAudioEnabled = mAudioGroupBox->isChecked();
const AVCodec *currentAudioCodec = nullptr;
Expand Down Expand Up @@ -486,6 +494,56 @@ void OutputSettingsDialog::updateAvailableSampleFormats() {
}
}

void OutputSettingsDialog::updateAvailableVideoProfiles()
{
mVideoProfileComboBox->clear();
mVideoProfileComboBox->addItem(tr("Default"), FF_PROFILE_UNKNOWN);

const AVCodec *currentCodec = nullptr;
if (mVideoCodecsComboBox->count() > 0) {
currentCodec = mVideoCodecsList.at(mVideoCodecsComboBox->currentIndex());
}
if (!currentCodec) { return; }
switch (currentCodec->id) {
case AV_CODEC_ID_H264:
mVideoProfileComboBox->addItem(tr("Baseline"), FF_PROFILE_H264_BASELINE);
mVideoProfileComboBox->addItem(tr("Main"), FF_PROFILE_H264_MAIN);
mVideoProfileComboBox->addItem(tr("High"), FF_PROFILE_H264_HIGH);
break;
case AV_CODEC_ID_PRORES:
mVideoProfileComboBox->addItem(tr("Proxy"), FF_PROFILE_PRORES_PROXY);
mVideoProfileComboBox->addItem(tr("LT"), FF_PROFILE_PRORES_LT);
mVideoProfileComboBox->addItem(tr("Standard"), FF_PROFILE_PRORES_STANDARD);
mVideoProfileComboBox->addItem(tr("HQ"), FF_PROFILE_PRORES_HQ);
mVideoProfileComboBox->addItem(tr("4444"), FF_PROFILE_PRORES_4444);
mVideoProfileComboBox->addItem(tr("XQ"), FF_PROFILE_PRORES_XQ);
break;
case AV_CODEC_ID_AV1:
mVideoProfileComboBox->addItem(tr("Main"), FF_PROFILE_AV1_MAIN);
mVideoProfileComboBox->addItem(tr("High"), FF_PROFILE_AV1_HIGH);
mVideoProfileComboBox->addItem(tr("Professional"), FF_PROFILE_AV1_PROFESSIONAL);
break;
case AV_CODEC_ID_VP9:
mVideoProfileComboBox->addItem(tr("0"), FF_PROFILE_VP9_0);
mVideoProfileComboBox->addItem(tr("1"), FF_PROFILE_VP9_1);
mVideoProfileComboBox->addItem(tr("2"), FF_PROFILE_VP9_2);
mVideoProfileComboBox->addItem(tr("3"), FF_PROFILE_VP9_3);
break;
case AV_CODEC_ID_MPEG4:
mVideoProfileComboBox->addItem(tr("Simple"), FF_PROFILE_MPEG4_SIMPLE);
mVideoProfileComboBox->addItem(tr("Core"), FF_PROFILE_MPEG4_CORE);
mVideoProfileComboBox->addItem(tr("Main"), FF_PROFILE_MPEG4_MAIN);
break;
case AV_CODEC_ID_VC1:
mVideoProfileComboBox->addItem(tr("Simple"), FF_PROFILE_VC1_SIMPLE);
mVideoProfileComboBox->addItem(tr("Main"), FF_PROFILE_VC1_MAIN);
mVideoProfileComboBox->addItem(tr("Complex"), FF_PROFILE_VC1_COMPLEX);
mVideoProfileComboBox->addItem(tr("Advanced"), FF_PROFILE_VC1_ADVANCED);
break;
default:;
}
}

void OutputSettingsDialog::updateAvailableAudioBitrates() {
const auto lastSet = mAudioBitrateComboBox->currentData();
mAudioBitrateComboBox->clear();
Expand Down
3 changes: 3 additions & 0 deletions src/app/GUI/RenderWidgets/outputsettingsdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class OutputSettingsDialog : public QDialog {
void updateAvailableAudioCodecs();
void updateAvailableSampleRates();
void updateAvailableSampleFormats();
void updateAvailableVideoProfiles();
void updateAvailableAudioBitrates();
void updateAvailableAudioChannelLayouts();

Expand Down Expand Up @@ -99,6 +100,8 @@ class OutputSettingsDialog : public QDialog {
QComboBox *mPixelFormatsComboBox = nullptr;
QLabel *mBitrateLabel = nullptr;
QDoubleSpinBox *mBitrateSpinBox = nullptr;
QLabel *mVideoProfileLabel = nullptr;
QComboBox *mVideoProfileComboBox = nullptr;

QGroupBox *mAudioGroupBox = nullptr;
TwoColumnLayout *mAudioSettingsLayout = nullptr;
Expand Down
4 changes: 3 additions & 1 deletion src/app/GUI/RenderWidgets/outputsettingsdisplaywidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ void OutputSettingsDisplayWidget::setOutputSettings(const OutputSettings &settin
if(!settings.fVideoCodec) {
setVideoCodecText("-");
} else {
setVideoCodecText(QString(settings.fVideoCodec->name));
setVideoCodecText(QString(settings.fVideoCodec->name),
settings.fVideoCodec,
settings.fVideoProfile);
}
const char *pixelFormat = av_get_pix_fmt_name(settings.fVideoPixelFormat);
if(!pixelFormat) {
Expand Down
120 changes: 120 additions & 0 deletions src/app/GUI/RenderWidgets/outputsettingsdisplaywidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,126 @@ class OutputSettingsDisplayWidget : public QWidget {
mVideoCodecLabel->setText("<b>Video codec:</b><br>" + txt);
}

const QString getVideoProfileName(const AVCodec *codec,
int profile)
{
if (profile < 0 || !codec) { return QString(); }
switch (codec->id) {
case AV_CODEC_ID_H264:
switch (profile) {
case FF_PROFILE_H264_BASELINE:
return tr("Baseline");
break;
case FF_PROFILE_H264_MAIN:
return tr("Main");
break;
case FF_PROFILE_H264_HIGH:
return tr("High");
break;
default:;
}
break;
case AV_CODEC_ID_PRORES:
switch (profile) {
case FF_PROFILE_PRORES_PROXY:
return tr("Proxy");
break;
case FF_PROFILE_PRORES_LT:
return tr("LT");
break;
case FF_PROFILE_PRORES_STANDARD:
return tr("Standard");
break;
case FF_PROFILE_PRORES_HQ:
return tr("HQ");
break;
case FF_PROFILE_PRORES_4444:
return tr("4444");
break;
case FF_PROFILE_PRORES_XQ:
return tr("XQ");
break;
default:;
}
break;
case AV_CODEC_ID_AV1:
switch (profile) {
case FF_PROFILE_AV1_MAIN:
return tr("Main");
break;
case FF_PROFILE_AV1_HIGH:
return tr("High");
break;
case FF_PROFILE_AV1_PROFESSIONAL:
return tr("Professional");
break;
default:;
}
break;
case AV_CODEC_ID_VP9:
switch (profile) {
case FF_PROFILE_VP9_0:
return tr("0");
break;
case FF_PROFILE_VP9_1:
return tr("1");
break;
case FF_PROFILE_VP9_2:
return tr("2");
break;
case FF_PROFILE_VP9_3:
return tr("3");
break;
default:;
}
break;
case AV_CODEC_ID_MPEG4:
switch (profile) {
case FF_PROFILE_MPEG4_SIMPLE:
return tr("Simple");
break;
case FF_PROFILE_MPEG4_CORE:
return tr("Core");
break;
case FF_PROFILE_MPEG4_MAIN:
return tr("Main");
break;
default:;
}
break;
case AV_CODEC_ID_VC1:
switch (profile) {
case FF_PROFILE_VC1_SIMPLE:
return tr("Simple");
break;
case FF_PROFILE_VC1_MAIN:
return tr("Main");
break;
case FF_PROFILE_VC1_COMPLEX:
return tr("Complex");
break;
case FF_PROFILE_VC1_ADVANCED:
return tr("Advanced");
break;
default:;
}
break;
default:;
}
return QString();
}
void setVideoCodecText(const QString &txt,
const AVCodec *codec,
int profile)
{
QString label = "<b>%1:</b><br>%2";
QString profileName = getVideoProfileName(codec, profile);
if (!profileName.isEmpty()) {
label.append(QString(" (%1)").arg(profileName));
}
mVideoCodecLabel->setText(label.arg(tr("Video codec"), txt));
}

void setPixelFormatText(const QString &txt) {
mVideoPixelFormatLabel->setText("<b>Pixel format:</b><br>" + txt);
}
Expand Down
1 change: 1 addition & 0 deletions src/core/ReadWrite/evformat.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ namespace EvFormat {
colorizeInfluence = 23,
transformEffects = 24,
transformEffects2 = 25,
codecProfile = 26,

nextVersion
};
Expand Down
8 changes: 8 additions & 0 deletions src/core/outputsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
*/

#include "outputsettings.h"
#include "ReadWrite/evformat.h"
#include "appsupport.h"

QList<qsptr<OutputSettingsProfile>> OutputSettingsProfile::sOutputProfiles;
Expand Down Expand Up @@ -116,6 +117,7 @@ void OutputSettings::write(eWriteStream &dst) const
dst << (fVideoCodec ? fVideoCodec->id : -1);
dst.write(&fVideoPixelFormat, sizeof(AVPixelFormat));
dst << fVideoBitrate;
dst << fVideoProfile;

dst << fAudioEnabled;
dst << (fAudioCodec ? fAudioCodec->id : -1);
Expand All @@ -137,6 +139,9 @@ void OutputSettings::read(eReadStream &src)
fVideoCodec = avcodec_find_encoder(avVideoCodecId);
src.read(&fVideoPixelFormat, sizeof(AVPixelFormat));
src >> fVideoBitrate;
if (src.evFileVersion() >= EvFormat::codecProfile) {
src >> fVideoProfile;
}

src >> fAudioEnabled;
int audioCodecId; src >> audioCodecId;
Expand Down Expand Up @@ -178,6 +183,8 @@ void OutputSettingsProfile::save()
av_get_pix_fmt_name(mSettings.fVideoPixelFormat));
profile.setValue(QString::fromUtf8("video_bitrate"),
mSettings.fVideoBitrate);
profile.setValue(QString::fromUtf8("video_profile"),
mSettings.fVideoProfile);
}
profile.setValue(QString::fromUtf8("audio_enabled"),
mSettings.fAudioEnabled);
Expand Down Expand Up @@ -246,6 +253,7 @@ void OutputSettingsProfile::load(const QString &path)
.toUtf8()
.data());
mSettings.fVideoBitrate = profile.value(QString::fromUtf8("video_bitrate")).toInt();
mSettings.fVideoProfile = profile.value(QString::fromUtf8("video_profile")).toInt();
}
mSettings.fAudioEnabled = profileAudioEnabled;
if (mSettings.fAudioEnabled) {
Expand Down
1 change: 1 addition & 0 deletions src/core/outputsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ struct CORE_EXPORT OutputSettings
const AVCodec *fVideoCodec = nullptr;
AVPixelFormat fVideoPixelFormat = AV_PIX_FMT_NONE;
int fVideoBitrate = 0;
int fVideoProfile = FF_PROFILE_UNKNOWN;

bool fAudioEnabled = false;
const AVCodec *fAudioCodec = nullptr;
Expand Down
5 changes: 5 additions & 0 deletions src/core/videoencoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,11 @@ static void addVideoStream(OutputStream * const ost,
ost->fStream->time_base = renSettings.fTimeBase;
c->time_base = ost->fStream->time_base;

// set video codec profile (if any)
if (outSettings.fVideoProfile >= 0) {
c->profile = outSettings.fVideoProfile;
}

c->gop_size = 12; /* emit one intra frame every twelve frames at most */
c->pix_fmt = outSettings.fVideoPixelFormat;//RGBA;
if(c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
Expand Down

0 comments on commit 29ae228

Please sign in to comment.