diff --git a/obs/CMakeLists.txt b/obs/CMakeLists.txt index e48c36d02cfc68f3d52e260e40c6861c666a283d..189d5cb44aeb0971a0df97884272ef4ab77ba5c8 100644 --- a/obs/CMakeLists.txt +++ b/obs/CMakeLists.txt @@ -189,6 +189,7 @@ endif() target_link_libraries(obs libobs + libff Qt5::Widgets Qt5::Network ${obs_PLATFORM_LIBRARIES}) diff --git a/obs/data/locale/en-US.ini b/obs/data/locale/en-US.ini index 6745a30d767311b4ae5f39fd9241366a33564c66..48e6bc44cefd56f0d9cad1219ffe967178b7c9b3 100644 --- a/obs/data/locale/en-US.ini +++ b/obs/data/locale/en-US.ini @@ -276,9 +276,17 @@ Basic.Settings.Output.Adv.Recording.UseStreamEncoder="(Use stream encoder)" Basic.Settings.Output.Adv.FFmpeg.SaveFilter.Common="Common recording formats" Basic.Settings.Output.Adv.FFmpeg.SaveFilter.All="All Files" Basic.Settings.Output.Adv.FFmpeg.SavePathURL="File path or URL" -Basic.Settings.Output.Adv.FFmpeg.VEncoder="Video Encoder (blank=default)" +Basic.Settings.Output.Adv.FFmpeg.Format="Container Format" +Basic.Settings.Output.Adv.FFmpeg.FormatAudio="Audio" +Basic.Settings.Output.Adv.FFmpeg.FormatVideo="Video" +Basic.Settings.Output.Adv.FFmpeg.FormatDefault="Default Format" +Basic.Settings.Output.Adv.FFmpeg.FormatDesc="Container Format Description" +Basic.Settings.Output.Adv.FFmpeg.FormatDescDef="Audio/Video Codec guessed from File path or URL" +Basic.Settings.Output.Adv.FFmpeg.AVEncoderDefault="Default Encoder" +Basic.Settings.Output.Adv.FFmpeg.AVEncoderDisable="Disable Encoder" +Basic.Settings.Output.Adv.FFmpeg.VEncoder="Video Encoder" Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings="Video Encoder Settings (if any)" -Basic.Settings.Output.Adv.FFmpeg.AEncoder="Audio Encoder (blank=default)" +Basic.Settings.Output.Adv.FFmpeg.AEncoder="Audio Encoder" Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings="Audio Encoder Settings (if any)" # basic mode 'video' settings diff --git a/obs/forms/OBSBasicSettings.ui b/obs/forms/OBSBasicSettings.ui index 65813850ab83993075370ff9600ba353bfd73243..f516e9ae99d5859899b4bef22662ee26b31c3779 100644 --- a/obs/forms/OBSBasicSettings.ui +++ b/obs/forms/OBSBasicSettings.ui @@ -1241,13 +1241,20 @@ + + + Basic.Settings.Output.Adv.FFmpeg.Format + + + + Basic.Settings.Output.VideoBitrate - + 0 @@ -1260,34 +1267,60 @@ - + + + + + 0 + 0 + + + + Qt::RightToLeft + + + Basic.Settings.Output.Adv.Rescale + + + + + + + false + + + true + + + + Basic.Settings.Output.Adv.FFmpeg.VEncoder - - + + - + Basic.Settings.Output.Adv.FFmpeg.VEncoderSettings - + - + Basic.Settings.Output.AudioBitrate - + 32 @@ -1303,60 +1336,14 @@ - + Basic.Settings.Output.Adv.AudioTrack - - - - Basic.Settings.Output.Adv.FFmpeg.AEncoder - - - - - - - - - - Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings - - - - - - - - - - 0 - 0 - - - - Qt::RightToLeft - - - Basic.Settings.Output.Adv.Rescale - - - - - - - false - - - true - - - - @@ -1411,6 +1398,43 @@ + + + + Basic.Settings.Output.Adv.FFmpeg.AEncoder + + + + + + + Basic.Settings.Output.Adv.FFmpeg.AEncoderSettings + + + + + + + + + + + + + + + + + + + + Basic.Settings.Output.Adv.FFmpeg.FormatDesc + + + + + + diff --git a/obs/window-basic-main-outputs.cpp b/obs/window-basic-main-outputs.cpp index 8c0232e91c5aa6caf81ce535d746caee3f84398a..ad2979f06da907486f4624845659ee61826b6ac6 100644 --- a/obs/window-basic-main-outputs.cpp +++ b/obs/window-basic-main-outputs.cpp @@ -495,8 +495,14 @@ inline void AdvancedOutput::SetupFFmpeg() "FFRescale"); const char *rescaleRes = config_get_string(main->Config(), "AdvOut", "FFRescaleRes"); + const char *formatName = config_get_string(main->Config(), "AdvOut", + "FFFormat"); + const char *mimeType = config_get_string(main->Config(), "AdvOut", + "FFFormatMimeType"); 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 aBitrate = config_get_int(main->Config(), "AdvOut", @@ -505,16 +511,22 @@ inline void AdvancedOutput::SetupFFmpeg() "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"); obs_data_t *settings = obs_data_create(); obs_data_set_string(settings, "url", url); + obs_data_set_string(settings, "format_name", formatName); + obs_data_set_string(settings, "format_mime_type", mimeType); obs_data_set_int(settings, "video_bitrate", vBitrate); obs_data_set_string(settings, "video_encoder", vEncoder); + obs_data_set_int(settings, "video_encoder_id", vEncoderId); obs_data_set_string(settings, "video_settings", vEncCustom); obs_data_set_int(settings, "audio_bitrate", aBitrate); obs_data_set_string(settings, "audio_encoder", aEncoder); + obs_data_set_int(settings, "audio_encoder_id", aEncoderId); obs_data_set_string(settings, "audio_settings", aEncCustom); if (rescale && rescaleRes && *rescaleRes) { diff --git a/obs/window-basic-settings.cpp b/obs/window-basic-settings.cpp index b9abc6dac61353117fa60791c4a29288174f3003..05f7138d766315fcc86fcbb2788374b33262d8c8 100644 --- a/obs/window-basic-settings.cpp +++ b/obs/window-basic-settings.cpp @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include #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()) { + 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()) { + 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(); + 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(); + 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(); + 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(); + 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(); + 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) diff --git a/obs/window-basic-settings.hpp b/obs/window-basic-settings.hpp index b36e8e75b6d9e8c2b31608814c53b38408a76945..f6da637e1beb20ea27a436e1b72eee7cdbefc912 100644 --- a/obs/window-basic-settings.hpp +++ b/obs/window-basic-settings.hpp @@ -23,6 +23,8 @@ #include #include +#include + #include class OBSBasic; @@ -32,6 +34,23 @@ class OBSPropertiesView; #include "ui_OBSBasicSettings.h" +class OBSFFDeleter +{ +public: + void operator()(const ff_format_desc *format) + { + ff_format_desc_free(format); + } + void operator()(const ff_codec_desc *codec) + { + ff_codec_desc_free(codec); + } +}; +using OBSFFCodecDesc = std::unique_ptr; +using OBSFFFormatDesc = std::unique_ptr; + class OBSBasicSettings : public QDialog { Q_OBJECT @@ -49,6 +68,8 @@ private: bool loading = true; std::string savedTheme; + OBSFFFormatDesc formats; + OBSPropertiesView *streamProperties = nullptr; OBSPropertiesView *streamEncoderProps = nullptr; OBSPropertiesView *recordEncoderProps = nullptr; @@ -63,6 +84,9 @@ private: const char *value); void SaveSpinBox(QSpinBox *widget, const char *section, const char *value); + void SaveFormat(QComboBox *combo); + void SaveEncoder(QComboBox *combo, const char *section, + const char *value); inline bool Changed() const { @@ -93,6 +117,8 @@ private: void LoadServiceTypes(); void LoadEncoderTypes(); void LoadColorRanges(); + void LoadFormats(); + void ReloadCodecs(const ff_format_desc *formatDesc); void LoadGeneralSettings(); void LoadStream1Settings(); @@ -117,6 +143,9 @@ private: void LoadAdvOutputRecordingEncoderProperties(); void LoadAdvOutputFFmpegSettings(); void LoadAdvOutputAudioSettings(); + void SetAdvOutputFFmpegEnablement( + ff_codec_type encoderType, bool enabled, + bool enableEncode = false); /* audio */ void LoadListValues(QComboBox *widget, obs_property_t *prop, @@ -154,6 +183,9 @@ private slots: void on_advOutFFPathBrowse_clicked(); void on_advOutEncoder_currentIndexChanged(int idx); void on_advOutRecEncoder_currentIndexChanged(int idx); + void on_advOutFFFormat_currentIndexChanged(int idx); + void on_advOutFFAEncoder_currentIndexChanged(int idx); + void on_advOutFFVEncoder_currentIndexChanged(int idx); void on_baseResolution_editTextChanged(const QString &text);