diff --git a/obs/data/locale/en-US.ini b/obs/data/locale/en-US.ini
index a4ac9cde8..f140d603f 100644
--- a/obs/data/locale/en-US.ini
+++ b/obs/data/locale/en-US.ini
@@ -309,6 +309,17 @@ Basic.Settings.Output.Mode.Simple="Simple"
Basic.Settings.Output.Mode.Adv="Advanced"
Basic.Settings.Output.Mode.FFmpeg="FFmpeg Output"
Basic.Settings.Output.Simple.SavePath="Recording Path"
+Basic.Settings.Output.Simple.RecordingQuality="Recording Quality"
+Basic.Settings.Output.Simple.RecordingQuality.Stream="Same as stream"
+Basic.Settings.Output.Simple.RecordingQuality.Small="High Quality, Medium File Size"
+Basic.Settings.Output.Simple.RecordingQuality.HQ="Indistinguishable Quality, Large File Size"
+Basic.Settings.Output.Simple.RecordingQuality.Lossless="Lossless Quality, Tremendously Large File Size"
+Basic.Settings.Output.Simple.Warn.Encoder="Warning: Recording with a software encoder at a different quality than the stream will require extra CPU usage if you stream and record at the same time."
+Basic.Settings.Output.Simple.Warn.Lossless="Warning: Lossless quality generates tremendously large file sizes! Lossless quality can use upward of 7 gigabytes of disk space per minute at high resolutions and framerates. Lossless is not recommended for long recordings unless you have a very large amount of disk space available."
+Basic.Settings.Output.Simple.Warn.Lossless.Msg="Are you sure you want to use lossless quality?"
+Basic.Settings.Output.Simple.Warn.Lossless.Title="Lossless quality warning!"
+Basic.Settings.Output.Simple.Encoder.Software="Software (x264)"
+Basic.Settings.Output.Simple.Encoder.SoftwareLowCPU="Software (x264 low CPU usage preset, increases file size)"
Basic.Settings.Output.VideoBitrate="Video Bitrate"
Basic.Settings.Output.AudioBitrate="Audio Bitrate"
Basic.Settings.Output.Reconnect="Automatically Reconnect"
diff --git a/obs/forms/OBSBasicSettings.ui b/obs/forms/OBSBasicSettings.ui
index 9e5991dae..a41afd5b9 100644
--- a/obs/forms/OBSBasicSettings.ui
+++ b/obs/forms/OBSBasicSettings.ui
@@ -6,8 +6,8 @@
0
0
- 937
- 653
+ 896
+ 667
@@ -363,6 +363,342 @@
0
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Basic.Settings.Output.Adv.Streaming
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
-
+
+
+
+ 170
+ 0
+
+
+
+ Basic.Settings.Output.VideoBitrate
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
+ 200
+
+
+ 1000000
+
+
+ 2000
+
+
+
+ -
+
+
+ Basic.Settings.Output.AudioBitrate
+
+
+
+ -
+
+
+ 8
+
+
-
+
+ 32
+
+
+ -
+
+ 48
+
+
+ -
+
+ 64
+
+
+ -
+
+ 80
+
+
+ -
+
+ 96
+
+
+ -
+
+ 112
+
+
+ -
+
+ 128
+
+
+ -
+
+ 160
+
+
+ -
+
+ 192
+
+
+ -
+
+ 256
+
+
+ -
+
+ 320
+
+
+
+
+ -
+
+
+ Basic.Settings.Output.Advanced
+
+
+ true
+
+
+
+ -
+
+
-
+
+ ultrafast
+
+
+ -
+
+ superfast
+
+
+ -
+
+ veryfast
+
+
+ -
+
+ faster
+
+
+ -
+
+ fast
+
+
+ -
+
+ medium
+
+
+ -
+
+ slow
+
+
+ -
+
+ slower
+
+
+
+
+ -
+
+
+ true
+
+
+ Basic.Settings.Output.EncoderPreset
+
+
+
+ -
+
+
+ Basic.Settings.Output.CustomEncoderSettings
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Basic.Settings.Output.Adv.Recording
+
+
+
+ QFormLayout::AllNonFixedFieldsGrow
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
-
+
+
-
+
+
+ true
+
+
+
+ -
+
+
+ true
+
+
+ Browse
+
+
+
+
+
+ -
+
+
+
+ 170
+ 0
+
+
+
+ Basic.Settings.Output.Simple.SavePath
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+ -
+
+
-
+
+ flv
+
+
+ -
+
+ mp4
+
+
+ -
+
+ mov
+
+
+ -
+
+ mkv
+
+
+ -
+
+ ts
+
+
+
+
+ -
+
+
+ Basic.Settings.Output.Format
+
+
+
+ -
+
+
+ -
+
+
+ Basic.Settings.Output.Simple.RecordingQuality
+
+
+
+ -
+
+
+ -
+
+
+ Basic.Settings.Output.Encoder
+
+
+
+
+
+
+ -
+
+
+ 10
+
+
+ 10
+
+
+ 10
+
+
+ 10
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
-
@@ -378,260 +714,6 @@
0
-
-
-
-
-
- 0
- 0
-
-
-
-
- QFormLayout::AllNonFixedFieldsGrow
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
-
- 170
- 0
-
-
-
- Basic.Settings.Output.Simple.SavePath
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
-
-
- true
-
-
-
- -
-
-
- true
-
-
- Browse
-
-
-
-
-
- -
-
-
- Basic.Settings.Output.Format
-
-
-
- -
-
-
-
-
- flv
-
-
- -
-
- mp4
-
-
- -
-
- mov
-
-
- -
-
- mkv
-
-
- -
-
- ts
-
-
-
-
- -
-
-
- Basic.Settings.Output.VideoBitrate
-
-
-
- -
-
-
- 200
-
-
- 1000000
-
-
- 2000
-
-
-
- -
-
-
- Basic.Settings.Output.AudioBitrate
-
-
-
- -
-
-
- 8
-
-
-
-
- 32
-
-
- -
-
- 48
-
-
- -
-
- 64
-
-
- -
-
- 80
-
-
- -
-
- 96
-
-
- -
-
- 112
-
-
- -
-
- 128
-
-
- -
-
- 160
-
-
- -
-
- 192
-
-
- -
-
- 256
-
-
- -
-
- 320
-
-
-
-
- -
-
-
- Basic.Settings.Output.Advanced
-
-
- true
-
-
-
- -
-
-
- true
-
-
- Basic.Settings.Output.EncoderPreset
-
-
-
- -
-
-
-
-
- ultrafast
-
-
- -
-
- superfast
-
-
- -
-
- veryfast
-
-
- -
-
- faster
-
-
- -
-
- fast
-
-
- -
-
- medium
-
-
- -
-
- slow
-
-
- -
-
- slower
-
-
-
-
- -
-
-
- Basic.Settings.Output.CustomEncoderSettings
-
-
-
- -
-
-
-
-
-
@@ -2138,8 +2220,8 @@
0
0
- 98
- 28
+ 63
+ 16
@@ -2526,8 +2608,8 @@
0
0
- 711
- 566
+ 735
+ 618
diff --git a/obs/window-basic-main-outputs.cpp b/obs/window-basic-main-outputs.cpp
index cbdd18823..ebd8f1514 100644
--- a/obs/window-basic-main-outputs.cpp
+++ b/obs/window-basic-main-outputs.cpp
@@ -104,18 +104,36 @@ static bool CreateAACEncoder(OBSEncoder &res, string &id, int bitrate,
/* ------------------------------------------------------------------------ */
struct SimpleOutput : BasicOutputHandler {
- OBSEncoder aac;
- OBSEncoder h264;
+ OBSEncoder aacStreaming;
+ OBSEncoder h264Streaming;
+ OBSEncoder aacRecording;
+ OBSEncoder h264Recording;
- string aacEncoderID;
+ string aacRecEncID;
+ string aacStreamEncID;
+
+ string videoEncoder;
+ string videoQuality;
+ bool usingRecordingPreset = false;
+ bool ffmpegOutput = false;
+ bool lowCPUx264 = false;
SimpleOutput(OBSBasic *main_);
+ int CalcCRF(int crf);
+
+ void UpdateRecordingSettings_x264_crf(int crf);
+ void UpdateRecordingSettings();
+ void UpdateRecordingAudioSettings();
virtual void Update() override;
void SetupOutputs();
int GetAudioBitrate() const;
+ void LoadRecordingPreset_x264();
+ void LoadRecordingPreset_Lossless();
+ void LoadRecordingPreset();
+
virtual bool StartStreaming(obs_service_t *service) override;
virtual bool StartRecording() override;
virtual void StopStreaming() override;
@@ -125,6 +143,68 @@ struct SimpleOutput : BasicOutputHandler {
virtual bool RecordingActive() const override;
};
+void SimpleOutput::LoadRecordingPreset_Lossless()
+{
+ fileOutput = obs_output_create("ffmpeg_output",
+ "simple_ffmpeg_output", nullptr, nullptr);
+ if (!fileOutput)
+ throw "Failed to create recording FFmpeg output "
+ "(simple output)";
+ obs_output_release(fileOutput);
+
+ obs_data_t *settings = obs_data_create();
+ obs_data_set_string(settings, "format_name", "avi");
+ obs_data_set_string(settings, "video_encoder", "huffyuv");
+ obs_data_set_int(settings, "audio_bitrate", 512);
+ obs_data_set_string(settings, "audio_encoder", "ac3");
+
+ obs_output_update(fileOutput, settings);
+ obs_data_release(settings);
+}
+
+void SimpleOutput::LoadRecordingPreset_x264()
+{
+ h264Recording = obs_video_encoder_create("obs_x264",
+ "simple_h264_recording", nullptr, nullptr);
+ if (!h264Recording)
+ throw "Failed to create h264 recording encoder (simple output)";
+ obs_encoder_release(h264Recording);
+
+ if (!CreateAACEncoder(aacRecording, aacRecEncID, 192,
+ "simple_aac_recording", 0))
+ throw "Failed to create aac recording encoder (simple output)";
+}
+
+void SimpleOutput::LoadRecordingPreset()
+{
+ const char *quality = config_get_string(main->Config(), "SimpleOutput",
+ "RecQuality");
+ const char *encoder = config_get_string(main->Config(), "SimpleOutput",
+ "RecEncoder");
+
+ videoEncoder = encoder;
+ videoQuality = quality;
+ ffmpegOutput = false;
+
+ if (strcmp(quality, "Stream") == 0) {
+ h264Recording = h264Streaming;
+ aacRecording = aacStreaming;
+ usingRecordingPreset = false;
+ return;
+
+ } else if (strcmp(quality, "Lossless") == 0) {
+ LoadRecordingPreset_Lossless();
+ usingRecordingPreset = true;
+ ffmpegOutput = true;
+ return;
+
+ } else {
+ lowCPUx264 = strcmp(encoder, SIMPLE_ENCODER_X264_LOWCPU) == 0;
+ LoadRecordingPreset_x264();
+ usingRecordingPreset = true;
+ }
+}
+
SimpleOutput::SimpleOutput(OBSBasic *main_) : BasicOutputHandler(main_)
{
streamOutput = obs_output_create("rtmp_output", "simple_stream",
@@ -133,21 +213,15 @@ SimpleOutput::SimpleOutput(OBSBasic *main_) : BasicOutputHandler(main_)
throw "Failed to create stream output (simple output)";
obs_output_release(streamOutput);
- fileOutput = obs_output_create("ffmpeg_muxer", "simple_file_output",
- nullptr, nullptr);
- if (!fileOutput)
- throw "Failed to create recording output (simple output)";
- obs_output_release(fileOutput);
+ h264Streaming = obs_video_encoder_create("obs_x264",
+ "simple_h264_stream", nullptr, nullptr);
+ if (!h264Streaming)
+ throw "Failed to create h264 streaming encoder (simple output)";
+ obs_encoder_release(h264Streaming);
- h264 = obs_video_encoder_create("obs_x264", "simple_h264", nullptr,
- nullptr);
- if (!h264)
- throw "Failed to create h264 encoder (simple output)";
- obs_encoder_release(h264);
-
- if (!CreateAACEncoder(aac, aacEncoderID, GetAudioBitrate(),
+ if (!CreateAACEncoder(aacStreaming, aacStreamEncID, GetAudioBitrate(),
"simple_aac", 0))
- throw "Failed to create audio encoder (simple output)";
+ throw "Failed to create aac streaming encoder (simple output)";
streamDelayStarting.Connect(obs_output_get_signal_handler(streamOutput),
"starting", OBSStreamStarting, this);
@@ -159,6 +233,17 @@ SimpleOutput::SimpleOutput(OBSBasic *main_) : BasicOutputHandler(main_)
stopStreaming.Connect(obs_output_get_signal_handler(streamOutput),
"stop", OBSStopStreaming, this);
+ LoadRecordingPreset();
+
+ if (!ffmpegOutput) {
+ fileOutput = obs_output_create("ffmpeg_muxer",
+ "simple_file_output", nullptr, nullptr);
+ if (!fileOutput)
+ throw "Failed to create recording output "
+ "(simple output)";
+ obs_output_release(fileOutput);
+ }
+
startRecording.Connect(obs_output_get_signal_handler(fileOutput),
"start", OBSStartRecording, this);
stopRecording.Connect(obs_output_get_signal_handler(fileOutput),
@@ -202,20 +287,89 @@ void SimpleOutput::Update()
enum video_format format = video_output_get_format(video);
if (format != VIDEO_FORMAT_NV12 && format != VIDEO_FORMAT_I420)
- obs_encoder_set_preferred_video_format(h264, VIDEO_FORMAT_NV12);
+ obs_encoder_set_preferred_video_format(h264Streaming,
+ VIDEO_FORMAT_NV12);
- obs_encoder_update(h264, h264Settings);
- obs_encoder_update(aac, aacSettings);
+ obs_encoder_update(h264Streaming, h264Settings);
+ obs_encoder_update(aacStreaming, aacSettings);
obs_data_release(h264Settings);
obs_data_release(aacSettings);
}
+void SimpleOutput::UpdateRecordingAudioSettings()
+{
+ obs_data_t *settings = obs_data_create();
+ obs_data_set_int(settings, "bitrate", 192);
+ obs_data_set_bool(settings, "cbr", true);
+
+ obs_encoder_update(aacRecording, settings);
+
+ obs_data_release(settings);
+}
+
+#define CROSS_DIST_CUTOFF 2000.0
+
+int SimpleOutput::CalcCRF(int crf)
+{
+ int cx = config_get_uint(main->Config(), "Video", "OutputCX");
+ int cy = config_get_uint(main->Config(), "Video", "OutputCY");
+ double fCX = double(cx);
+ double fCY = double(cy);
+
+ if (lowCPUx264)
+ crf -= 2;
+
+ double crossDist = sqrt(fCX * fCX + fCY * fCY);
+ double crfResReduction =
+ fmin(CROSS_DIST_CUTOFF, crossDist) / CROSS_DIST_CUTOFF;
+ crfResReduction = (1.0 - crfResReduction) * 10.0;
+
+ return crf - int(crfResReduction);
+}
+
+void SimpleOutput::UpdateRecordingSettings_x264_crf(int crf)
+{
+ obs_data_t *settings = obs_data_create();
+ obs_data_set_int(settings, "bitrate", 1000);
+ obs_data_set_int(settings, "buffer_size", 0);
+ obs_data_set_int(settings, "crf", crf);
+ obs_data_set_bool(settings, "use_bufsize", true);
+ obs_data_set_bool(settings, "cbr", false);
+ obs_data_set_string(settings, "profile", "high");
+ obs_data_set_string(settings, "preset",
+ lowCPUx264 ? "ultrafast" : "veryfast");
+
+ obs_encoder_update(h264Recording, settings);
+
+ obs_data_release(settings);
+}
+
+void SimpleOutput::UpdateRecordingSettings()
+{
+ if (astrcmp_n(videoEncoder.c_str(), "x264", 4) == 0) {
+ if (videoQuality == "Small")
+ UpdateRecordingSettings_x264_crf(CalcCRF(23));
+ else if (videoQuality == "HQ")
+ UpdateRecordingSettings_x264_crf(CalcCRF(16));
+ }
+}
+
inline void SimpleOutput::SetupOutputs()
{
SimpleOutput::Update();
- obs_encoder_set_video(h264, obs_get_video());
- obs_encoder_set_audio(aac, obs_get_audio());
+ obs_encoder_set_video(h264Streaming, obs_get_video());
+ obs_encoder_set_audio(aacStreaming, obs_get_audio());
+
+ if (usingRecordingPreset) {
+ if (ffmpegOutput) {
+ obs_output_set_media(fileOutput, obs_get_video(),
+ obs_get_audio());
+ } else {
+ obs_encoder_set_video(h264Recording, obs_get_video());
+ obs_encoder_set_audio(aacRecording, obs_get_audio());
+ }
+ }
}
bool SimpleOutput::StartStreaming(obs_service_t *service)
@@ -223,8 +377,8 @@ bool SimpleOutput::StartStreaming(obs_service_t *service)
if (!Active())
SetupOutputs();
- obs_output_set_video_encoder(streamOutput, h264);
- obs_output_set_audio_encoder(streamOutput, aac, 0);
+ obs_output_set_video_encoder(streamOutput, h264Streaming);
+ obs_output_set_audio_encoder(streamOutput, aacStreaming, 0);
obs_output_set_service(streamOutput, service);
bool reconnect = config_get_bool(main->Config(), "Output",
@@ -257,6 +411,13 @@ bool SimpleOutput::StartStreaming(obs_service_t *service)
bool SimpleOutput::StartRecording()
{
+ if (usingRecordingPreset) {
+ if (!ffmpegOutput)
+ UpdateRecordingSettings();
+ } else if (!obs_output_active(streamOutput)) {
+ Update();
+ }
+
if (!Active())
SetupOutputs();
@@ -283,15 +444,18 @@ bool SimpleOutput::StartRecording()
if (lastChar != '/' && lastChar != '\\')
strPath += "/";
- strPath += GenerateTimeDateFilename(format);
+ strPath += GenerateTimeDateFilename(ffmpegOutput ? "avi" : format);
SetupOutputs();
- obs_output_set_video_encoder(fileOutput, h264);
- obs_output_set_audio_encoder(fileOutput, aac, 0);
+ if (!ffmpegOutput) {
+ obs_output_set_video_encoder(fileOutput, h264Recording);
+ obs_output_set_audio_encoder(fileOutput, aacRecording, 0);
+ }
obs_data_t *settings = obs_data_create();
- obs_data_set_string(settings, "path", strPath.c_str());
+ obs_data_set_string(settings, ffmpegOutput ? "url" : "path",
+ strPath.c_str());
obs_output_update(fileOutput, settings);
diff --git a/obs/window-basic-main.cpp b/obs/window-basic-main.cpp
index 8aaa5b4a0..8efd71287 100644
--- a/obs/window-basic-main.cpp
+++ b/obs/window-basic-main.cpp
@@ -659,6 +659,10 @@ bool OBSBasic::InitBasicConfigDefaults()
false);
config_set_default_string(basicConfig, "SimpleOutput", "Preset",
"veryfast");
+ config_set_default_string(basicConfig, "SimpleOutput", "RecQuality",
+ "Stream");
+ config_set_default_string(basicConfig, "SimpleOutput", "RecEncoder",
+ SIMPLE_ENCODER_X264);
config_set_default_bool (basicConfig, "AdvOut", "ApplyServiceSettings",
true);
diff --git a/obs/window-basic-main.hpp b/obs/window-basic-main.hpp
index 981d35e65..0421b2e28 100644
--- a/obs/window-basic-main.hpp
+++ b/obs/window-basic-main.hpp
@@ -47,6 +47,9 @@ class QNetworkReply;
#define AUX_AUDIO_2 Str("AuxAudioDevice2")
#define AUX_AUDIO_3 Str("AuxAudioDevice3")
+#define SIMPLE_ENCODER_X264 "x264"
+#define SIMPLE_ENCODER_X264_LOWCPU "x264_lowcpu"
+
struct BasicOutputHandler;
enum class QtDataRole {
diff --git a/obs/window-basic-settings.cpp b/obs/window-basic-settings.cpp
index 341e4d4af..43e05e60b 100644
--- a/obs/window-basic-settings.cpp
+++ b/obs/window-basic-settings.cpp
@@ -272,6 +272,8 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
HookWidget(ui->simpleOutAdvanced, CHECK_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->simpleOutPreset, COMBO_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->simpleOutCustom, EDIT_CHANGED, OUTPUTS_CHANGED);
+ HookWidget(ui->simpleOutRecQuality, COMBO_CHANGED, OUTPUTS_CHANGED);
+ HookWidget(ui->simpleOutRecEncoder, COMBO_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->advOutEncoder, COMBO_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->advOutUseRescale, CHECK_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->advOutRescale, CBEDIT_CHANGED, OUTPUTS_CHANGED);
@@ -426,6 +428,14 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
hotkeyUnregistered.Connect(obs_get_signal_handler(),
"hotkey_unregister", ReloadHotkeysIgnore, this);
+ FillSimpleRecordingValues();
+ connect(ui->simpleOutRecQuality, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(SimpleRecordingQualityChanged()));
+ connect(ui->simpleOutRecQuality, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(SimpleRecordingQualityLosslessWarning(int)));
+ connect(ui->simpleOutRecEncoder, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(SimpleRecordingEncoderChanged()));
+
LoadSettings(false);
// Add warning checks to advanced output recording section controls
@@ -438,6 +448,8 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
connect(ui->advOutRecTrack4, SIGNAL(clicked()),
this, SLOT(AdvOutRecCheckWarnings()));
AdvOutRecCheckWarnings();
+
+ SimpleRecordingQualityChanged();
}
void OBSBasicSettings::SaveCombo(QComboBox *widget, const char *section,
@@ -1006,6 +1018,10 @@ void OBSBasicSettings::LoadSimpleOutputSettings()
"Preset");
const char *custom = config_get_string(main->Config(), "SimpleOutput",
"x264Settings");
+ const char *recQual = config_get_string(main->Config(), "SimpleOutput",
+ "RecQuality");
+ const char *recEnc = config_get_string(main->Config(), "SimpleOutput",
+ "RecEncoder");
ui->simpleOutputPath->setText(path);
ui->simpleOutputVBitrate->setValue(videoBitrate);
@@ -1019,6 +1035,14 @@ void OBSBasicSettings::LoadSimpleOutputSettings()
ui->simpleOutAdvanced->setChecked(advanced);
ui->simpleOutPreset->setCurrentText(preset);
ui->simpleOutCustom->setText(custom);
+
+ idx = ui->simpleOutRecQuality->findData(QString(recQual));
+ if (idx == -1) idx = 0;
+ ui->simpleOutRecQuality->setCurrentIndex(idx);
+
+ idx = ui->simpleOutRecEncoder->findData(QString(recEnc));
+ if (idx == -1) idx = 0;
+ ui->simpleOutRecEncoder->setCurrentIndex(idx);
}
void OBSBasicSettings::LoadAdvOutputStreamingSettings()
@@ -2078,6 +2102,8 @@ void OBSBasicSettings::SaveOutputSettings()
SaveCheckBox(ui->simpleOutAdvanced, "SimpleOutput", "UseAdvanced");
SaveCombo(ui->simpleOutPreset, "SimpleOutput", "Preset");
SaveEdit(ui->simpleOutCustom, "SimpleOutput", "x264Settings");
+ SaveComboData(ui->simpleOutRecQuality, "SimpleOutput", "RecQuality");
+ SaveComboData(ui->simpleOutRecEncoder, "SimpleOutput", "RecEncoder");
SaveCheckBox(ui->advOutApplyService, "AdvOut", "ApplyServiceSettings");
SaveComboData(ui->advOutEncoder, "AdvOut", "Encoder");
@@ -2750,3 +2776,111 @@ void OBSBasicSettings::UpdateStreamDelayEstimate()
else
UpdateAdvOutStreamDelayEstimate();
}
+
+void OBSBasicSettings::FillSimpleRecordingValues()
+{
+#define ADD_QUALITY(str) \
+ ui->simpleOutRecQuality->addItem( \
+ QTStr("Basic.Settings.Output.Simple.RecordingQuality." \
+ str), \
+ QString(str));
+#define ENCODER_STR(str) QTStr("Basic.Settings.Output.Simple.Encoder." str)
+
+ ADD_QUALITY("Stream");
+ ADD_QUALITY("Small");
+ ADD_QUALITY("HQ");
+ ADD_QUALITY("Lossless");
+
+ ui->simpleOutRecEncoder->addItem(
+ ENCODER_STR("Software"),
+ QString(SIMPLE_ENCODER_X264));
+ ui->simpleOutRecEncoder->addItem(
+ ENCODER_STR("SoftwareLowCPU"),
+ QString(SIMPLE_ENCODER_X264_LOWCPU));
+#undef ADD_QUALITY
+#undef ENCODER_STR
+}
+
+void OBSBasicSettings::SimpleRecordingQualityChanged()
+{
+ QString qual = ui->simpleOutRecQuality->currentData().toString();
+ bool streamQuality = qual == "Stream";
+ bool losslessQuality = !streamQuality && qual == "Lossless";
+
+ bool showEncoder = !streamQuality && !losslessQuality;
+ ui->simpleOutRecEncoder->setVisible(showEncoder);
+ ui->simpleOutRecEncoderLabel->setVisible(showEncoder);
+ ui->simpleOutRecFormat->setVisible(!losslessQuality);
+ ui->simpleOutRecFormatLabel->setVisible(!losslessQuality);
+
+ SimpleRecordingEncoderChanged();
+}
+
+#define SIMPLE_OUTPUT_WARNING(str) \
+ QTStr("Basic.Settings.Output.Simple.Warn." str)
+
+void OBSBasicSettings::SimpleRecordingEncoderChanged()
+{
+ QString qual = ui->simpleOutRecQuality->currentData().toString();
+ QString warning;
+
+ delete simpleOutRecWarning;
+
+ if (qual == "Stream") {
+ return;
+
+ } else if (qual == "Lossless") {
+ warning = SIMPLE_OUTPUT_WARNING("Lossless");
+ warning += "\n\n";
+ warning += SIMPLE_OUTPUT_WARNING("Encoder");
+
+ } else {
+ QString enc = ui->simpleOutRecEncoder->currentData().toString();
+ if (enc != SIMPLE_ENCODER_X264 &&
+ enc != SIMPLE_ENCODER_X264_LOWCPU)
+ return;
+
+ warning = SIMPLE_OUTPUT_WARNING("Encoder");
+ }
+
+ simpleOutRecWarning = new QLabel(warning, this);
+ simpleOutRecWarning->setObjectName("warningLabel");
+ simpleOutRecWarning->setWordWrap(true);
+ ui->simpleOutInfoLayout->addWidget(simpleOutRecWarning);
+}
+
+void OBSBasicSettings::SimpleRecordingQualityLosslessWarning(int idx)
+{
+ if (idx == lastSimpleRecQualityIdx || idx == -1)
+ return;
+
+ QString qual = ui->simpleOutRecQuality->itemData(idx).toString();
+
+ if (loading) {
+ lastSimpleRecQualityIdx = idx;
+ return;
+ }
+
+ if (qual == "Lossless") {
+ QMessageBox::StandardButton button;
+
+ QString warningString =
+ SIMPLE_OUTPUT_WARNING("Lossless") +
+ QString("\n\n") +
+ SIMPLE_OUTPUT_WARNING("Lossless.Msg");
+
+ button = QMessageBox::question(this,
+ SIMPLE_OUTPUT_WARNING("Lossless.Title"),
+ warningString,
+ QMessageBox::Yes | QMessageBox::No);
+
+ if (button == QMessageBox::No) {
+ QMetaObject::invokeMethod(ui->simpleOutRecQuality,
+ "setCurrentIndex", Qt::QueuedConnection,
+ Q_ARG(int, lastSimpleRecQualityIdx));
+ return;
+ }
+ }
+
+ lastSimpleRecQualityIdx = idx;
+}
diff --git a/obs/window-basic-settings.hpp b/obs/window-basic-settings.hpp
index fee3595e2..662fe601c 100644
--- a/obs/window-basic-settings.hpp
+++ b/obs/window-basic-settings.hpp
@@ -97,6 +97,8 @@ private:
bool loading = true;
std::string savedTheme;
+ int lastSimpleRecQualityIdx = 0;
+
OBSFFFormatDesc formats;
OBSPropertiesView *streamProperties = nullptr;
@@ -104,6 +106,7 @@ private:
OBSPropertiesView *recordEncoderProps = nullptr;
QPointer advOutRecWarning;
+ QPointer simpleOutRecWarning;
using AudioSource_t =
std::tuple