mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-09-24 23:31:36 +08:00
UI: Add Format, Audio and Video ComboBoxes
Adds ComboBoxes for selecting format and audio/video codecs. The ComboBoxes also show only valid codec combinations for a particular container format.
This commit is contained in:
@@ -25,6 +25,9 @@
|
||||
#include <QCloseEvent>
|
||||
#include <QFileDialog>
|
||||
#include <QDirIterator>
|
||||
#include <QVariant>
|
||||
#include <QTreeView>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
#include "obs-app.hpp"
|
||||
#include "platform.hpp"
|
||||
@@ -37,6 +40,51 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
// Used for QVariant in codec comboboxes
|
||||
namespace {
|
||||
struct FormatDesc {
|
||||
const char *name = nullptr;
|
||||
const char *mimeType = nullptr;
|
||||
const ff_format_desc *desc = nullptr;
|
||||
|
||||
inline FormatDesc() = default;
|
||||
inline FormatDesc(const char *name, const char *mimeType,
|
||||
const ff_format_desc *desc = nullptr)
|
||||
: name(name), mimeType(mimeType), desc(desc) {}
|
||||
|
||||
bool operator==(const FormatDesc &f) const
|
||||
{
|
||||
if ((name == nullptr) ^ (f.name == nullptr))
|
||||
return false;
|
||||
if (name != nullptr && strcmp(name, f.name) != 0)
|
||||
return false;
|
||||
if ((mimeType == nullptr) ^ (f.mimeType == nullptr))
|
||||
return false;
|
||||
if (mimeType != nullptr && strcmp(mimeType, f.mimeType) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
struct CodecDesc {
|
||||
const char *name = nullptr;
|
||||
int id = 0;
|
||||
|
||||
inline CodecDesc() = default;
|
||||
inline CodecDesc(const char *name, int id) : name(name), id(id) {}
|
||||
|
||||
bool operator==(const CodecDesc &codecDesc) const
|
||||
{
|
||||
if ((name == nullptr) ^ (codecDesc.name == nullptr))
|
||||
return false;
|
||||
if (id != codecDesc.id)
|
||||
return false;
|
||||
return name == nullptr || strcmp(name, codecDesc.name) == 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
Q_DECLARE_METATYPE(FormatDesc)
|
||||
Q_DECLARE_METATYPE(CodecDesc)
|
||||
|
||||
/* parses "[width]x[height]", string, i.e. 1024x768 */
|
||||
static bool ConvertResText(const char *res, uint32_t &cx, uint32_t &cy)
|
||||
{
|
||||
@@ -102,6 +150,40 @@ static inline QString GetComboData(QComboBox *combo)
|
||||
return combo->itemData(idx).toString();
|
||||
}
|
||||
|
||||
static int FindEncoder(QComboBox *combo, const char *name, int id)
|
||||
{
|
||||
CodecDesc codecDesc(name, id);
|
||||
for(int i = 0; i < combo->count(); i++) {
|
||||
QVariant v = combo->itemData(i);
|
||||
if (!v.isNull()) {
|
||||
if (codecDesc == v.value<CodecDesc>()) {
|
||||
return i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static CodecDesc GetDefaultCodecDesc(const ff_format_desc *formatDesc,
|
||||
ff_codec_type codecType)
|
||||
{
|
||||
int id = 0;
|
||||
switch (codecType) {
|
||||
case FF_CODEC_AUDIO:
|
||||
id = ff_format_desc_audio(formatDesc);
|
||||
break;
|
||||
case FF_CODEC_VIDEO:
|
||||
id = ff_format_desc_video(formatDesc);
|
||||
break;
|
||||
default:
|
||||
return CodecDesc();
|
||||
}
|
||||
|
||||
return CodecDesc(ff_format_desc_get_default_name(formatDesc, codecType),
|
||||
id);
|
||||
}
|
||||
|
||||
void OBSBasicSettings::HookWidget(QWidget *widget, const char *signal,
|
||||
const char *slot)
|
||||
{
|
||||
@@ -173,17 +255,18 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
|
||||
HookWidget(ui->advOutRecTrack3, CHECK_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutRecTrack4, CHECK_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutFFURL, EDIT_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutFFFormat, COMBO_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutFFVBitrate, SCROLL_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutFFUseRescale, CHECK_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutFFRescale, CBEDIT_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutFFVEncoder, EDIT_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutFFVEncoder, COMBO_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutFFVCfg, EDIT_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutFFABitrate, SCROLL_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutFFTrack1, CHECK_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutFFTrack2, CHECK_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutFFTrack3, CHECK_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutFFTrack4, CHECK_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutFFAEncoder, EDIT_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutFFAEncoder, COMBO_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutFFACfg, EDIT_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutTrack1Bitrate, COMBO_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->advOutTrack1Name, EDIT_CHANGED, OUTPUTS_CHANGED);
|
||||
@@ -219,9 +302,13 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
|
||||
//Apply button disabled until change.
|
||||
EnableApplyButton(false);
|
||||
|
||||
// Initialize libff library
|
||||
ff_init();
|
||||
|
||||
LoadServiceTypes();
|
||||
LoadEncoderTypes();
|
||||
LoadColorRanges();
|
||||
LoadFormats();
|
||||
LoadSettings(false);
|
||||
}
|
||||
|
||||
@@ -320,6 +407,122 @@ void OBSBasicSettings::LoadColorRanges()
|
||||
ui->colorRange->addItem(CS_FULL_STR, "Full");
|
||||
}
|
||||
|
||||
#define AV_FORMAT_DEFAULT_STR \
|
||||
QTStr("Basic.Settings.Output.Adv.FFmpeg.FormatDefault")
|
||||
#define AUDIO_STR \
|
||||
QTStr("Basic.Settings.Output.Adv.FFmpeg.FormatAudio")
|
||||
#define VIDEO_STR \
|
||||
QTStr("Basic.Settings.Output.Adv.FFmpeg.FormatVideo")
|
||||
|
||||
void OBSBasicSettings::LoadFormats()
|
||||
{
|
||||
formats.reset(ff_format_supported());
|
||||
const ff_format_desc *format = formats.get();
|
||||
|
||||
while(format != nullptr) {
|
||||
bool audio = ff_format_desc_has_audio(format);
|
||||
bool video = ff_format_desc_has_video(format);
|
||||
FormatDesc formatDesc(ff_format_desc_name(format),
|
||||
ff_format_desc_mime_type(format),
|
||||
format);
|
||||
if (audio || video) {
|
||||
QString itemText(ff_format_desc_name(format));
|
||||
if (audio ^ video)
|
||||
itemText += QString(" (%1)").arg(
|
||||
audio ? AUDIO_STR : VIDEO_STR);
|
||||
|
||||
ui->advOutFFFormat->addItem(itemText,
|
||||
qVariantFromValue(formatDesc));
|
||||
}
|
||||
|
||||
format = ff_format_desc_next(format);
|
||||
}
|
||||
|
||||
ui->advOutFFFormat->model()->sort(0);
|
||||
|
||||
ui->advOutFFFormat->insertItem(0, AV_FORMAT_DEFAULT_STR);
|
||||
}
|
||||
|
||||
static void AddCodec(QComboBox *combo, const ff_codec_desc *codec_desc)
|
||||
{
|
||||
QString itemText(ff_codec_desc_name(codec_desc));
|
||||
if (ff_codec_desc_is_alias(codec_desc))
|
||||
itemText += QString(" (%1)").arg(
|
||||
ff_codec_desc_base_name(codec_desc));
|
||||
|
||||
CodecDesc cd(ff_codec_desc_name(codec_desc),
|
||||
ff_codec_desc_id(codec_desc));
|
||||
|
||||
combo->addItem(itemText, qVariantFromValue(cd));
|
||||
}
|
||||
|
||||
#define AV_ENCODER_DEFAULT_STR \
|
||||
QTStr("Basic.Settings.Output.Adv.FFmpeg.AVEncoderDefault")
|
||||
|
||||
static void AddDefaultCodec(QComboBox *combo, const ff_format_desc *formatDesc,
|
||||
ff_codec_type codecType)
|
||||
{
|
||||
CodecDesc cd = GetDefaultCodecDesc(formatDesc, codecType);
|
||||
|
||||
int existingIdx = FindEncoder(combo, cd.name, cd.id);
|
||||
if (existingIdx >= 0)
|
||||
combo->removeItem(existingIdx);
|
||||
|
||||
combo->addItem(QString("%1 (%2)").arg(cd.name, AV_ENCODER_DEFAULT_STR),
|
||||
qVariantFromValue(cd));
|
||||
}
|
||||
|
||||
#define AV_ENCODER_DISABLE_STR \
|
||||
QTStr("Basic.Settings.Output.Adv.FFmpeg.AVEncoderDisable")
|
||||
|
||||
void OBSBasicSettings::ReloadCodecs(const ff_format_desc *formatDesc)
|
||||
{
|
||||
ui->advOutFFAEncoder->blockSignals(true);
|
||||
ui->advOutFFVEncoder->blockSignals(true);
|
||||
ui->advOutFFAEncoder->clear();
|
||||
ui->advOutFFVEncoder->clear();
|
||||
|
||||
if (formatDesc == nullptr)
|
||||
return;
|
||||
|
||||
OBSFFCodecDesc codecDescs(ff_codec_supported(formatDesc));
|
||||
|
||||
const ff_codec_desc *codec = codecDescs.get();
|
||||
|
||||
while(codec != nullptr) {
|
||||
switch (ff_codec_desc_type(codec)) {
|
||||
case FF_CODEC_AUDIO:
|
||||
AddCodec(ui->advOutFFAEncoder, codec);
|
||||
break;
|
||||
case FF_CODEC_VIDEO:
|
||||
AddCodec(ui->advOutFFVEncoder, codec);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
codec = ff_codec_desc_next(codec);
|
||||
}
|
||||
|
||||
if (ff_format_desc_has_audio(formatDesc))
|
||||
AddDefaultCodec(ui->advOutFFAEncoder, formatDesc,
|
||||
FF_CODEC_AUDIO);
|
||||
if (ff_format_desc_has_video(formatDesc))
|
||||
AddDefaultCodec(ui->advOutFFVEncoder, formatDesc,
|
||||
FF_CODEC_VIDEO);
|
||||
|
||||
ui->advOutFFAEncoder->model()->sort(0);
|
||||
ui->advOutFFVEncoder->model()->sort(0);
|
||||
|
||||
QVariant disable = qVariantFromValue(CodecDesc());
|
||||
|
||||
ui->advOutFFAEncoder->insertItem(0, AV_ENCODER_DISABLE_STR, disable);
|
||||
ui->advOutFFVEncoder->insertItem(0, AV_ENCODER_DISABLE_STR, disable);
|
||||
|
||||
ui->advOutFFAEncoder->blockSignals(false);
|
||||
ui->advOutFFVEncoder->blockSignals(false);
|
||||
}
|
||||
|
||||
void OBSBasicSettings::LoadLanguageList()
|
||||
{
|
||||
const char *currentLang = App()->GetLocale();
|
||||
@@ -783,9 +986,38 @@ void OBSBasicSettings::LoadAdvOutputRecordingEncoderProperties()
|
||||
SetComboByValue(ui->advOutRecEncoder, encoder);
|
||||
}
|
||||
|
||||
static void SelectFormat(QComboBox *combo, const char *name,
|
||||
const char *mimeType)
|
||||
{
|
||||
FormatDesc formatDesc(name, mimeType);
|
||||
|
||||
for(int i = 0; i < combo->count(); i++) {
|
||||
QVariant v = combo->itemData(i);
|
||||
if (!v.isNull()) {
|
||||
if (formatDesc == v.value<FormatDesc>()) {
|
||||
combo->setCurrentIndex(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
combo->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
static void SelectEncoder(QComboBox *combo, const char *name, int id)
|
||||
{
|
||||
int idx = FindEncoder(combo, name, id);
|
||||
if (idx >= 0)
|
||||
combo->setCurrentIndex(idx);
|
||||
}
|
||||
|
||||
void OBSBasicSettings::LoadAdvOutputFFmpegSettings()
|
||||
{
|
||||
const char *url = config_get_string(main->Config(), "AdvOut", "FFURL");
|
||||
const char *format = config_get_string(main->Config(), "AdvOut",
|
||||
"FFFormat");
|
||||
const char *mimeType = config_get_string(main->Config(), "AdvOut",
|
||||
"FFFormatMimeType");
|
||||
int videoBitrate = config_get_int(main->Config(), "AdvOut",
|
||||
"FFVBitrate");
|
||||
bool rescale = config_get_bool(main->Config(), "AdvOut",
|
||||
@@ -794,6 +1026,8 @@ void OBSBasicSettings::LoadAdvOutputFFmpegSettings()
|
||||
"FFRescaleRes");
|
||||
const char *vEncoder = config_get_string(main->Config(), "AdvOut",
|
||||
"FFVEncoder");
|
||||
int vEncoderId = config_get_int(main->Config(), "AdvOut",
|
||||
"FFVEncoderId");
|
||||
const char *vEncCustom = config_get_string(main->Config(), "AdvOut",
|
||||
"FFVCustom");
|
||||
int audioBitrate = config_get_int(main->Config(), "AdvOut",
|
||||
@@ -802,18 +1036,21 @@ void OBSBasicSettings::LoadAdvOutputFFmpegSettings()
|
||||
"FFAudioTrack");
|
||||
const char *aEncoder = config_get_string(main->Config(), "AdvOut",
|
||||
"FFAEncoder");
|
||||
int aEncoderId = config_get_int(main->Config(), "AdvOut",
|
||||
"FFAEncoderId");
|
||||
const char *aEncCustom = config_get_string(main->Config(), "AdvOut",
|
||||
"FFACustom");
|
||||
|
||||
ui->advOutFFURL->setText(url);
|
||||
SelectFormat(ui->advOutFFFormat, format, mimeType);
|
||||
ui->advOutFFVBitrate->setValue(videoBitrate);
|
||||
ui->advOutFFUseRescale->setChecked(rescale);
|
||||
ui->advOutFFRescale->setEnabled(rescale);
|
||||
ui->advOutFFRescale->setCurrentText(rescaleRes);
|
||||
ui->advOutFFVEncoder->setText(vEncoder);
|
||||
SelectEncoder(ui->advOutFFVEncoder, vEncoder, vEncoderId);
|
||||
ui->advOutFFVCfg->setText(vEncCustom);
|
||||
ui->advOutFFABitrate->setValue(audioBitrate);
|
||||
ui->advOutFFAEncoder->setText(aEncoder);
|
||||
SelectEncoder(ui->advOutFFAEncoder, aEncoder, aEncoderId);
|
||||
ui->advOutFFACfg->setText(aEncCustom);
|
||||
|
||||
switch (audioTrack) {
|
||||
@@ -887,6 +1124,34 @@ void OBSBasicSettings::LoadOutputSettings()
|
||||
loading = false;
|
||||
}
|
||||
|
||||
void OBSBasicSettings::SetAdvOutputFFmpegEnablement(
|
||||
ff_codec_type encoderType, bool enabled,
|
||||
bool enableEncoder)
|
||||
{
|
||||
bool rescale = config_get_bool(main->Config(), "AdvOut",
|
||||
"FFRescale");
|
||||
|
||||
switch (encoderType) {
|
||||
case FF_CODEC_VIDEO:
|
||||
ui->advOutFFVBitrate->setEnabled(enabled);
|
||||
ui->advOutFFUseRescale->setEnabled(enabled);
|
||||
ui->advOutFFRescale->setEnabled(enabled && rescale);
|
||||
ui->advOutFFVEncoder->setEnabled(enabled || enableEncoder);
|
||||
ui->advOutFFVCfg->setEnabled(enabled);
|
||||
break;
|
||||
case FF_CODEC_AUDIO:
|
||||
ui->advOutFFABitrate->setEnabled(enabled);
|
||||
ui->advOutFFAEncoder->setEnabled(enabled || enableEncoder);
|
||||
ui->advOutFFACfg->setEnabled(enabled);
|
||||
ui->advOutFFTrack1->setEnabled(enabled);
|
||||
ui->advOutFFTrack2->setEnabled(enabled);
|
||||
ui->advOutFFTrack3->setEnabled(enabled);
|
||||
ui->advOutFFTrack4->setEnabled(enabled);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void LoadListValue(QComboBox *widget, const char *text,
|
||||
const char *val)
|
||||
{
|
||||
@@ -1147,6 +1412,38 @@ static void SaveTrackIndex(config_t *config, const char *section,
|
||||
else if (check4->isChecked()) config_set_int(config, section, name, 4);
|
||||
}
|
||||
|
||||
void OBSBasicSettings::SaveFormat(QComboBox *combo)
|
||||
{
|
||||
QVariant v = combo->currentData();
|
||||
if (!v.isNull()) {
|
||||
FormatDesc desc = v.value<FormatDesc>();
|
||||
config_set_string(main->Config(), "AdvOut", "FFFormat",
|
||||
desc.name);
|
||||
config_set_string(main->Config(), "AdvOut", "FFFormatMimeType",
|
||||
desc.mimeType);
|
||||
} else {
|
||||
config_set_string(main->Config(), "AdvOut", "FFFormat",
|
||||
nullptr);
|
||||
config_set_string(main->Config(), "AdvOut", "FFFormatMimeType",
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void OBSBasicSettings::SaveEncoder(QComboBox *combo, const char *section,
|
||||
const char *value)
|
||||
{
|
||||
QVariant v = combo->currentData();
|
||||
CodecDesc cd;
|
||||
if (!v.isNull())
|
||||
cd = v.value<CodecDesc>();
|
||||
config_set_int(main->Config(), section,
|
||||
QT_TO_UTF8(QString("%1Id").arg(value)), cd.id);
|
||||
if (cd.id != 0)
|
||||
config_set_string(main->Config(), section, value, cd.name);
|
||||
else
|
||||
config_set_string(main->Config(), section, value, nullptr);
|
||||
}
|
||||
|
||||
void OBSBasicSettings::SaveOutputSettings()
|
||||
{
|
||||
config_set_string(main->Config(), "Output", "Mode",
|
||||
@@ -1190,13 +1487,14 @@ void OBSBasicSettings::SaveOutputSettings()
|
||||
ui->advOutRecTrack3, ui->advOutRecTrack4);
|
||||
|
||||
SaveEdit(ui->advOutFFURL, "AdvOut", "FFURL");
|
||||
SaveFormat(ui->advOutFFFormat);
|
||||
SaveSpinBox(ui->advOutFFVBitrate, "AdvOut", "FFVBitrate");
|
||||
SaveCheckBox(ui->advOutFFUseRescale, "AdvOut", "FFRescale");
|
||||
SaveCombo(ui->advOutFFRescale, "AdvOut", "FFRescaleRes");
|
||||
SaveEdit(ui->advOutFFVEncoder, "AdvOut", "FFVEncoder");
|
||||
SaveEncoder(ui->advOutFFVEncoder, "AdvOut", "FFVEncoder");
|
||||
SaveEdit(ui->advOutFFVCfg, "AdvOut", "FFVCustom");
|
||||
SaveSpinBox(ui->advOutFFABitrate, "AdvOut", "FFABitrate");
|
||||
SaveEdit(ui->advOutFFAEncoder, "AdvOut", "FFAEncoder");
|
||||
SaveEncoder(ui->advOutFFAEncoder, "AdvOut", "FFAEncoder");
|
||||
SaveEdit(ui->advOutFFACfg, "AdvOut", "FFACustom");
|
||||
SaveTrackIndex(main->Config(), "AdvOut", "FFAudioTrack",
|
||||
ui->advOutFFTrack1, ui->advOutFFTrack2,
|
||||
@@ -1442,6 +1740,59 @@ void OBSBasicSettings::on_advOutRecEncoder_currentIndexChanged(int idx)
|
||||
}
|
||||
}
|
||||
|
||||
#define DEFAULT_CONTAINER_STR \
|
||||
QTStr("Basic.Settings.Output.Adv.FFmpeg.FormatDescDef")
|
||||
|
||||
void OBSBasicSettings::on_advOutFFFormat_currentIndexChanged(int idx)
|
||||
{
|
||||
const QVariant itemDataVariant = ui->advOutFFFormat->itemData(idx);
|
||||
|
||||
if (!itemDataVariant.isNull()) {
|
||||
FormatDesc desc = itemDataVariant.value<FormatDesc>();
|
||||
SetAdvOutputFFmpegEnablement(FF_CODEC_AUDIO,
|
||||
ff_format_desc_has_audio(desc.desc),
|
||||
false);
|
||||
SetAdvOutputFFmpegEnablement(FF_CODEC_VIDEO,
|
||||
ff_format_desc_has_video(desc.desc),
|
||||
false);
|
||||
ReloadCodecs(desc.desc);
|
||||
ui->advOutFFFormatDesc->setText(ff_format_desc_long_name(
|
||||
desc.desc));
|
||||
|
||||
CodecDesc defaultAudioCodecDesc =
|
||||
GetDefaultCodecDesc(desc.desc, FF_CODEC_AUDIO);
|
||||
CodecDesc defaultVideoCodecDesc =
|
||||
GetDefaultCodecDesc(desc.desc, FF_CODEC_VIDEO);
|
||||
SelectEncoder(ui->advOutFFAEncoder, defaultAudioCodecDesc.name,
|
||||
defaultAudioCodecDesc.id);
|
||||
SelectEncoder(ui->advOutFFVEncoder, defaultVideoCodecDesc.name,
|
||||
defaultVideoCodecDesc.id);
|
||||
} else {
|
||||
ReloadCodecs(nullptr);
|
||||
ui->advOutFFFormatDesc->setText(DEFAULT_CONTAINER_STR);
|
||||
}
|
||||
}
|
||||
|
||||
void OBSBasicSettings::on_advOutFFAEncoder_currentIndexChanged(int idx)
|
||||
{
|
||||
const QVariant itemDataVariant = ui->advOutFFAEncoder->itemData(idx);
|
||||
if (!itemDataVariant.isNull()) {
|
||||
CodecDesc desc = itemDataVariant.value<CodecDesc>();
|
||||
SetAdvOutputFFmpegEnablement(FF_CODEC_AUDIO,
|
||||
desc.id != 0 || desc.name != nullptr, true);
|
||||
}
|
||||
}
|
||||
|
||||
void OBSBasicSettings::on_advOutFFVEncoder_currentIndexChanged(int idx)
|
||||
{
|
||||
const QVariant itemDataVariant = ui->advOutFFVEncoder->itemData(idx);
|
||||
if (!itemDataVariant.isNull()) {
|
||||
CodecDesc desc = itemDataVariant.value<CodecDesc>();
|
||||
SetAdvOutputFFmpegEnablement(FF_CODEC_VIDEO,
|
||||
desc.id != 0 || desc.name != nullptr, true);
|
||||
}
|
||||
}
|
||||
|
||||
#define INVALID_RES_STR "Basic.Settings.Video.InvalidResolution"
|
||||
|
||||
static bool ValidResolutions(Ui::OBSBasicSettings *ui)
|
||||
|
||||
Reference in New Issue
Block a user