diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini
index 988317099..8e781b05c 100644
--- a/UI/data/locale/en-US.ini
+++ b/UI/data/locale/en-US.ini
@@ -769,6 +769,7 @@ Basic.Settings.Output.Adv.Audio.Track3="Track 3"
Basic.Settings.Output.Adv.Audio.Track4="Track 4"
Basic.Settings.Output.Adv.Audio.Track5="Track 5"
Basic.Settings.Output.Adv.Audio.Track6="Track 6"
+Basic.Settings.Output.Adv.TwitchVodTrack="Twitch VOD Track"
# basic mode 'output' settings - advanced section - recording subsection
Basic.Settings.Output.Adv.Recording="Recording"
diff --git a/UI/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui
index 49ae397ee..83c6cd204 100644
--- a/UI/forms/OBSBasicSettings.ui
+++ b/UI/forms/OBSBasicSettings.ui
@@ -1907,7 +1907,7 @@
0
-
+
QFormLayout::AllNonFixedFieldsGrow
diff --git a/UI/window-basic-main-outputs.cpp b/UI/window-basic-main-outputs.cpp
index 8a127b72d..7df2a2c95 100644
--- a/UI/window-basic-main-outputs.cpp
+++ b/UI/window-basic-main-outputs.cpp
@@ -1054,6 +1054,7 @@ bool SimpleOutput::ReplayBufferActive() const
struct AdvancedOutput : BasicOutputHandler {
OBSEncoder streamAudioEnc;
+ OBSEncoder streamArchiveEnc;
OBSEncoder aacTrack[MAX_AUDIO_MIXES];
OBSEncoder h264Streaming;
OBSEncoder h264Recording;
@@ -1229,6 +1230,14 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
throw "Failed to create streaming audio encoder "
"(advanced output)";
+ id = "";
+ int vodTrack =
+ config_get_int(main->Config(), "AdvOut", "VodTrackIndex") - 1;
+ if (!CreateAACEncoder(streamArchiveEnc, id, GetAudioBitrate(vodTrack),
+ "avc_aac_archive", vodTrack))
+ throw "Failed to create archive audio encoder "
+ "(advanced output)";
+
startRecording.Connect(obs_output_get_signal_handler(fileOutput),
"start", OBSStartRecording, this);
stopRecording.Connect(obs_output_get_signal_handler(fileOutput), "stop",
@@ -1280,6 +1289,18 @@ void AdvancedOutput::Update()
UpdateAudioSettings();
}
+static inline bool ServiceSupportsVodTrack(const char *service)
+{
+ static const char *vodTrackServices[] = {"Twitch"};
+
+ for (const char *vodTrackService : vodTrackServices) {
+ if (astrcmpi(vodTrackService, service) == 0)
+ return true;
+ }
+
+ return false;
+}
+
inline void AdvancedOutput::SetupStreaming()
{
bool rescale = config_get_bool(main->Config(), "AdvOut", "Rescale");
@@ -1461,6 +1482,8 @@ inline void AdvancedOutput::UpdateAudioSettings()
"ApplyServiceSettings");
int streamTrackIndex =
config_get_int(main->Config(), "AdvOut", "TrackIndex");
+ int vodTrackIndex =
+ config_get_int(main->Config(), "AdvOut", "VodTrackIndex");
obs_data_t *settings[MAX_AUDIO_MIXES];
for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
@@ -1481,18 +1504,23 @@ inline void AdvancedOutput::UpdateAudioSettings()
}
for (size_t i = 0; i < MAX_AUDIO_MIXES; i++) {
+ int track = (int)(i + 1);
+
obs_encoder_update(aacTrack[i], settings[i]);
- if ((int)(i + 1) == streamTrackIndex) {
+ if (track == streamTrackIndex || track == vodTrackIndex) {
if (applyServiceSettings) {
obs_service_apply_encoder_settings(
main->GetService(), nullptr,
settings[i]);
}
-
- obs_encoder_update(streamAudioEnc, settings[i]);
}
+ if (track == streamTrackIndex)
+ obs_encoder_update(streamAudioEnc, settings[i]);
+ if (track == vodTrackIndex)
+ obs_encoder_update(streamArchiveEnc, settings[i]);
+
obs_data_release(settings[i]);
}
}
@@ -1505,6 +1533,7 @@ void AdvancedOutput::SetupOutputs()
for (size_t i = 0; i < MAX_AUDIO_MIXES; i++)
obs_encoder_set_audio(aacTrack[i], obs_get_audio());
obs_encoder_set_audio(streamAudioEnc, obs_get_audio());
+ obs_encoder_set_audio(streamArchiveEnc, obs_get_audio());
SetupStreaming();
@@ -1527,7 +1556,11 @@ int AdvancedOutput::GetAudioBitrate(size_t i) const
bool AdvancedOutput::SetupStreaming(obs_service_t *service)
{
int streamTrack =
- config_get_int(main->Config(), "AdvOut", "TrackIndex") - 1;
+ config_get_int(main->Config(), "AdvOut", "TrackIndex");
+ bool vodTrackEnabled =
+ config_get_bool(main->Config(), "AdvOut", "VodTrackEnabled");
+ int vodTrackIndex =
+ config_get_int(main->Config(), "AdvOut", "VodTrackIndex");
if (!useStreamEncoder ||
(!ffmpegOutput && !obs_output_active(fileOutput))) {
@@ -1609,7 +1642,7 @@ bool AdvancedOutput::SetupStreaming(obs_service_t *service)
streamAudioEnc = obs_audio_encoder_create(
id, "alt_audio_enc", nullptr,
- streamTrack, nullptr);
+ streamTrack - 1, nullptr);
if (!streamAudioEnc)
return false;
@@ -1626,6 +1659,23 @@ bool AdvancedOutput::SetupStreaming(obs_service_t *service)
obs_output_set_video_encoder(streamOutput, h264Streaming);
obs_output_set_audio_encoder(streamOutput, streamAudioEnc, 0);
+
+ const char *id = obs_service_get_id(service);
+ if (strcmp(id, "rtmp_custom") == 0) {
+ vodTrackEnabled = false;
+ } else {
+ obs_data_t *settings = obs_service_get_settings(service);
+ const char *service = obs_data_get_string(settings, "service");
+ if (!ServiceSupportsVodTrack(service))
+ vodTrackEnabled = false;
+ obs_data_release(settings);
+ }
+
+ if (vodTrackEnabled && streamTrack != vodTrackIndex)
+ obs_output_set_audio_encoder(streamOutput, streamArchiveEnc, 1);
+ else
+ obs_output_set_audio_encoder(streamOutput, nullptr, 1);
+
return true;
}
diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp
index a77363cdd..5f9f99d33 100644
--- a/UI/window-basic-main.cpp
+++ b/UI/window-basic-main.cpp
@@ -1301,6 +1301,7 @@ bool OBSBasic::InitBasicConfigDefaults()
true);
config_set_default_bool(basicConfig, "AdvOut", "UseRescale", false);
config_set_default_uint(basicConfig, "AdvOut", "TrackIndex", 1);
+ config_set_default_uint(basicConfig, "AdvOut", "VodTrackIndex", 2);
config_set_default_string(basicConfig, "AdvOut", "Encoder", "obs_x264");
config_set_default_string(basicConfig, "AdvOut", "RecType", "Standard");
diff --git a/UI/window-basic-settings-stream.cpp b/UI/window-basic-settings-stream.cpp
index b1586d6e9..071b03d96 100644
--- a/UI/window-basic-settings-stream.cpp
+++ b/UI/window-basic-settings-stream.cpp
@@ -71,6 +71,8 @@ void OBSBasicSettings::InitStreamPage()
SLOT(UpdateServerList()));
connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
SLOT(UpdateKeyLink()));
+ connect(ui->service, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(UpdateVodTrackSetting()));
connect(ui->customServer, SIGNAL(textChanged(const QString &)), this,
SLOT(UpdateKeyLink()));
connect(ui->customServer, SIGNAL(editingFinished(const QString &)),
@@ -141,6 +143,7 @@ void OBSBasicSettings::LoadStream1Settings()
UpdateKeyLink();
UpdateMoreInfoLink();
+ UpdateVodTrackSetting();
bool streamActive = obs_frontend_streaming_active();
ui->streamPage->setEnabled(!streamActive);
@@ -594,3 +597,56 @@ void OBSBasicSettings::on_useAuth_toggled()
ui->authPwLabel->setVisible(use_auth);
ui->authPwWidget->setVisible(use_auth);
}
+
+void OBSBasicSettings::UpdateVodTrackSetting()
+{
+ bool enableVodTrack = ui->service->currentText() == "Twitch";
+ bool wasEnabled = !!vodTrackCheckbox;
+
+ if (enableVodTrack == wasEnabled)
+ return;
+
+ if (!enableVodTrack) {
+ delete vodTrackCheckbox;
+ delete vodTrackContainer;
+ return;
+ }
+
+ vodTrackCheckbox = new QCheckBox(
+ QTStr("Basic.Settings.Output.Adv.TwitchVodTrack"));
+ vodTrackCheckbox->setLayoutDirection(Qt::RightToLeft);
+
+ vodTrackContainer = new QWidget();
+ QHBoxLayout *vodTrackLayout = new QHBoxLayout();
+ for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
+ vodTrack[i] = new QRadioButton(QString::number(i + 1));
+ vodTrackLayout->addWidget(vodTrack[i]);
+
+ HookWidget(vodTrack[i], SIGNAL(clicked(bool)),
+ SLOT(OutputsChanged()));
+ }
+
+ HookWidget(vodTrackCheckbox, SIGNAL(clicked(bool)),
+ SLOT(OutputsChanged()));
+
+ vodTrackLayout->addStretch();
+ vodTrackLayout->setContentsMargins(0, 0, 0, 0);
+
+ vodTrackContainer->setLayout(vodTrackLayout);
+
+ ui->advOutTopLayout->insertRow(2, vodTrackCheckbox, vodTrackContainer);
+
+ bool vodTrackEnabled =
+ config_get_bool(main->Config(), "AdvOut", "VodTrackEnabled");
+ vodTrackCheckbox->setChecked(vodTrackEnabled);
+ vodTrackContainer->setEnabled(vodTrackEnabled);
+
+ connect(vodTrackCheckbox, SIGNAL(clicked(bool)), vodTrackContainer,
+ SLOT(setEnabled(bool)));
+
+ int trackIndex =
+ config_get_int(main->Config(), "AdvOut", "VodTrackIndex");
+ for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
+ vodTrack[i]->setChecked((i + 1) == trackIndex);
+ }
+}
diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp
index 3a3890739..6c2c4290f 100644
--- a/UI/window-basic-settings.cpp
+++ b/UI/window-basic-settings.cpp
@@ -3386,6 +3386,13 @@ void OBSBasicSettings::SaveOutputSettings()
SaveEdit(ui->advOutTrack5Name, "AdvOut", "Track5Name");
SaveEdit(ui->advOutTrack6Name, "AdvOut", "Track6Name");
+ if (vodTrackCheckbox) {
+ SaveCheckBox(vodTrackCheckbox, "AdvOut", "VodTrackEnabled");
+ SaveTrackIndex(main->Config(), "AdvOut", "VodTrackIndex",
+ vodTrack[0], vodTrack[1], vodTrack[2],
+ vodTrack[3], vodTrack[4], vodTrack[5]);
+ }
+
SaveCheckBox(ui->advReplayBuf, "AdvOut", "RecRB");
SaveSpinBox(ui->advRBSecMax, "AdvOut", "RecRBTime");
SaveSpinBox(ui->advRBMegsMax, "AdvOut", "RecRBSize");
diff --git a/UI/window-basic-settings.hpp b/UI/window-basic-settings.hpp
index 89f679506..a8f098086 100644
--- a/UI/window-basic-settings.hpp
+++ b/UI/window-basic-settings.hpp
@@ -32,6 +32,7 @@
class OBSBasic;
class QAbstractButton;
+class QRadioButton;
class QComboBox;
class QCheckBox;
class QLabel;
@@ -156,6 +157,10 @@ private:
uint32_t outputCX = 0;
uint32_t outputCY = 0;
+ QPointer vodTrackCheckbox;
+ QPointer vodTrackContainer;
+ QPointer vodTrack[MAX_AUDIO_MIXES];
+
void SaveCombo(QComboBox *widget, const char *section,
const char *value);
void SaveComboData(QComboBox *widget, const char *section,
@@ -239,6 +244,7 @@ private:
private slots:
void UpdateServerList();
void UpdateKeyLink();
+ void UpdateVodTrackSetting();
void UpdateMoreInfoLink();
void on_show_clicked();
void on_authPwShow_clicked();