diff --git a/obs/data/locale/en-US.ini b/obs/data/locale/en-US.ini
index bbaea10ec..9d083d99a 100644
--- a/obs/data/locale/en-US.ini
+++ b/obs/data/locale/en-US.ini
@@ -42,6 +42,7 @@ Hide="Hide"
Untitled="Untitled"
New="New"
Duplicate="Duplicate"
+Enable="Enable"
# title bar strings
TitleBar.Profile="Profile"
@@ -391,6 +392,10 @@ Basic.Settings.Advanced.Video.ColorSpace="YUV Color Space"
Basic.Settings.Advanced.Video.ColorRange="YUV Color Range"
Basic.Settings.Advanced.Video.ColorRange.Partial="Partial"
Basic.Settings.Advanced.Video.ColorRange.Full="Full"
+Basic.Settings.Advanced.StreamDelay="Stream Delay"
+Basic.Settings.Advanced.StreamDelay.Duration="Duration (seconds)"
+Basic.Settings.Advanced.StreamDelay.Preserve="Preserve cutoff point (increase delay) when reconnecting"
+Basic.Settings.Advanced.StreamDelay.MemoryUsage="Estimated Memory Usage: %1 MB"
# advanced audio properties
Basic.AdvAudio="Advanced Audio Properties"
diff --git a/obs/forms/OBSBasicSettings.ui b/obs/forms/OBSBasicSettings.ui
index 646628996..779e78d05 100644
--- a/obs/forms/OBSBasicSettings.ui
+++ b/obs/forms/OBSBasicSettings.ui
@@ -2790,6 +2790,98 @@
+ -
+
+
+ Basic.Settings.Advanced.StreamDelay
+
+
+
-
+
+
+ Enable
+
+
+ true
+
+
+
+ -
+
+
+ Basic.Settings.Advanced.StreamDelay.Duration
+
+
+
+ -
+
+
+ true
+
+
+
+ 5
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+
+ 80
+ 0
+
+
+
+ s
+
+
+ 1
+
+
+ 1800
+
+
+
+ -
+
+
+ Estimated RAM goes here
+
+
+
+
+
+
+ -
+
+
+ Basic.Settings.Advanced.StreamDelay.Preserve
+
+
+
+
+
+
-
@@ -3222,8 +3314,56 @@
setCurrentIndex(int)
- 732
- 179
+ 250
+ 89
+
+
+ 250
+ 92
+
+
+
+
+ streamDelayEnable
+ toggled(bool)
+ label_56
+ setEnabled(bool)
+
+
+ 533
+ 273
+
+
+ 449
+ 301
+
+
+
+
+ streamDelayEnable
+ toggled(bool)
+ streamDelayPreserve
+ setEnabled(bool)
+
+
+ 578
+ 275
+
+
+ 593
+ 339
+
+
+
+
+ streamDelayEnable
+ toggled(bool)
+ widget_12
+ setEnabled(bool)
+
+
+ 517
+ 267
777
diff --git a/obs/window-basic-main.cpp b/obs/window-basic-main.cpp
index 0def42563..2f77cc11b 100644
--- a/obs/window-basic-main.cpp
+++ b/obs/window-basic-main.cpp
@@ -689,6 +689,10 @@ bool OBSBasic::InitBasicConfigDefaults()
config_set_default_uint (basicConfig, "Video", "BaseCX", cx);
config_set_default_uint (basicConfig, "Video", "BaseCY", cy);
+ config_set_default_bool (basicConfig, "Output", "DelayEnable", false);
+ config_set_default_uint (basicConfig, "Output", "DelaySec", 20);
+ config_set_default_bool (basicConfig, "Output", "DelayPreserve", true);
+
int i = 0;
uint32_t scale_cx = cx;
uint32_t scale_cy = cy;
diff --git a/obs/window-basic-settings.cpp b/obs/window-basic-settings.cpp
index 8a16616b9..7191dd2aa 100644
--- a/obs/window-basic-settings.cpp
+++ b/obs/window-basic-settings.cpp
@@ -346,6 +346,9 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
HookWidget(ui->colorFormat, COMBO_CHANGED, ADV_CHANGED);
HookWidget(ui->colorSpace, COMBO_CHANGED, ADV_CHANGED);
HookWidget(ui->colorRange, COMBO_CHANGED, ADV_CHANGED);
+ HookWidget(ui->streamDelayEnable, CHECK_CHANGED, ADV_CHANGED);
+ HookWidget(ui->streamDelaySec, SCROLL_CHANGED, ADV_CHANGED);
+ HookWidget(ui->streamDelayPreserve, CHECK_CHANGED, ADV_CHANGED);
#ifdef _WIN32
uint32_t winVer = GetWindowsVersion();
@@ -363,6 +366,23 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
}
#endif
+ connect(ui->streamDelaySec, SIGNAL(valueChanged(int)),
+ this, SLOT(UpdateStreamDelayEstimate()));
+ connect(ui->outputMode, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(UpdateStreamDelayEstimate()));
+ connect(ui->simpleOutputVBitrate, SIGNAL(valueChanged(int)),
+ this, SLOT(UpdateStreamDelayEstimate()));
+ connect(ui->simpleOutputABitrate, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(UpdateStreamDelayEstimate()));
+ connect(ui->advOutTrack1Bitrate, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(UpdateStreamDelayEstimate()));
+ connect(ui->advOutTrack2Bitrate, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(UpdateStreamDelayEstimate()));
+ connect(ui->advOutTrack3Bitrate, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(UpdateStreamDelayEstimate()));
+ connect(ui->advOutTrack4Bitrate, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(UpdateStreamDelayEstimate()));
+
//Apply button disabled until change.
EnableApplyButton(false);
@@ -1096,7 +1116,12 @@ void OBSBasicSettings::LoadAdvOutputStreamingEncoderProperties()
"streamEncoder.json");
ui->advOutputStreamTab->layout()->addWidget(streamEncoderProps);
+ connect(streamEncoderProps, SIGNAL(Changed()),
+ this, SLOT(UpdateStreamDelayEstimate()));
+
SetComboByValue(ui->advOutEncoder, encoder);
+
+ UpdateStreamDelayEstimate();
}
void OBSBasicSettings::LoadAdvOutputRecordingSettings()
@@ -1548,9 +1573,19 @@ void OBSBasicSettings::LoadAdvancedSettings()
"Video", "ColorSpace");
const char *videoColorRange = config_get_string(main->Config(),
"Video", "ColorRange");
+ bool enableDelay = config_get_bool(main->Config(), "Output",
+ "DelayEnable");
+ int delaySec = config_get_int(main->Config(), "Output",
+ "DelaySec");
+ bool preserveDelay = config_get_bool(main->Config(), "Output",
+ "DelayPreserve");
loading = true;
+ ui->streamDelaySec->setValue(delaySec);
+ ui->streamDelayPreserve->setChecked(preserveDelay);
+ ui->streamDelayEnable->setChecked(enableDelay);
+
ui->audioBufferingTime->setValue(audioBufferingTime);
SetComboByName(ui->colorFormat, videoColorFormat);
SetComboByName(ui->colorSpace, videoColorSpace);
@@ -1954,6 +1989,9 @@ void OBSBasicSettings::SaveAdvancedSettings()
SaveCombo(ui->colorFormat, "Video", "ColorFormat");
SaveCombo(ui->colorSpace, "Video", "ColorSpace");
SaveComboData(ui->colorRange, "Video", "ColorRange");
+ SaveCheckBox(ui->streamDelayEnable, "Output", "DelayEnable");
+ SaveSpinBox(ui->streamDelaySec, "Output", "DelaySec");
+ SaveCheckBox(ui->streamDelayPreserve, "Output", "DelayPreserve");
}
static inline const char *OutputModeFromIdx(int idx)
@@ -2701,3 +2739,55 @@ void OBSBasicSettings::AdvOutRecCheckWarnings()
formLayout->addRow(nullptr, advOutRecWarning);
}
}
+
+static inline QString MakeMemorySizeString(int bitrate, int seconds)
+{
+ QString str = QTStr("Basic.Settings.Advanced.StreamDelay.MemoryUsage");
+ int megabytes = bitrate * seconds / 1000 / 8;
+
+ return str.arg(QString::number(megabytes));
+}
+
+void OBSBasicSettings::UpdateSimpleOutStreamDelayEstimate()
+{
+ int seconds = ui->streamDelaySec->value();
+ int vBitrate = ui->simpleOutputVBitrate->value();
+ int aBitrate = ui->simpleOutputABitrate->currentText().toInt();
+
+ QString msg = MakeMemorySizeString(vBitrate + aBitrate, seconds);
+
+ ui->streamDelayInfo->setText(msg);
+}
+
+void OBSBasicSettings::UpdateAdvOutStreamDelayEstimate()
+{
+ if (!streamEncoderProps)
+ return;
+
+ OBSData settings = streamEncoderProps->GetSettings();
+ int trackIndex = config_get_int(main->Config(), "AdvOut", "TrackIndex");
+ QString aBitrateText;
+
+ switch (trackIndex) {
+ case 1: aBitrateText = ui->advOutTrack1Bitrate->currentText(); break;
+ case 2: aBitrateText = ui->advOutTrack2Bitrate->currentText(); break;
+ case 3: aBitrateText = ui->advOutTrack3Bitrate->currentText(); break;
+ case 4: aBitrateText = ui->advOutTrack4Bitrate->currentText(); break;
+ }
+
+ int seconds = ui->streamDelaySec->value();
+ int vBitrate = (int)obs_data_get_int(settings, "bitrate");
+ int aBitrate = aBitrateText.toInt();
+
+ QString msg = MakeMemorySizeString(vBitrate + aBitrate, seconds);
+
+ ui->streamDelayInfo->setText(msg);
+}
+
+void OBSBasicSettings::UpdateStreamDelayEstimate()
+{
+ if (ui->outputMode->currentIndex() == 0)
+ UpdateSimpleOutStreamDelayEstimate();
+ else
+ UpdateAdvOutStreamDelayEstimate();
+}
diff --git a/obs/window-basic-settings.hpp b/obs/window-basic-settings.hpp
index 200eea07b..0cacb6391 100644
--- a/obs/window-basic-settings.hpp
+++ b/obs/window-basic-settings.hpp
@@ -222,6 +222,9 @@ private:
void SaveAdvancedSettings();
void SaveSettings();
+ void UpdateSimpleOutStreamDelayEstimate();
+ void UpdateAdvOutStreamDelayEstimate();
+
private slots:
void on_theme_activated(int idx);
@@ -259,6 +262,8 @@ private slots:
void AdvancedChanged();
void AdvancedChangedRestart();
+ void UpdateStreamDelayEstimate();
+
void AdvOutRecCheckWarnings();
protected: