diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini
index c1e29ea24..e04cab93a 100644
--- a/UI/data/locale/en-US.ini
+++ b/UI/data/locale/en-US.ini
@@ -994,6 +994,7 @@ Basic.Settings.Output.Simple.Codec.AAC="AAC"
Basic.Settings.Output.Simple.Codec.AAC.Default="AAC (Default)"
Basic.Settings.Output.Simple.Codec.Opus="Opus"
Basic.Settings.Output.Simple.TwitchVodTrack="Twitch VOD Track (Uses Track 2)"
+Basic.Settings.Output.Simple.RecAudioTrack="Audio Track"
Basic.Settings.Output.Warn.EnforceResolutionFPS.Title="Incompatible Resolution/Framerate"
Basic.Settings.Output.Warn.EnforceResolutionFPS.Msg="This streaming service does not support your current output resolution and/or framerate. They will be changed to the closest compatible value:\n\n%1\n\nDo you want to continue?"
Basic.Settings.Output.Warn.EnforceResolutionFPS.Resolution="Resolution: %1"
diff --git a/UI/forms/OBSBasicSettings.ui b/UI/forms/OBSBasicSettings.ui
index 7eb799700..b09ab68f3 100644
--- a/UI/forms/OBSBasicSettings.ui
+++ b/UI/forms/OBSBasicSettings.ui
@@ -1939,6 +1939,217 @@
-
+
+
+ Basic.Settings.Output.Simple.RecAudioTrack
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 0
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ 1
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 2
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 3
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 4
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 5
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 6
+
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 1
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 2
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 3
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 4
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 5
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ 6
+
+
+
+
+
+
+
+ -
Basic.Settings.Output.CustomMuxerSettings
@@ -1948,10 +2159,10 @@
- -
+
-
- -
+
-
Basic.Settings.Output.UseReplayBuffer
@@ -7621,6 +7832,12 @@
simpleOutPreset
simpleOutAdvanced
simpleOutCustom
+ simpleOutRecTrack1
+ simpleOutRecTrack2
+ simpleOutRecTrack3
+ simpleOutRecTrack4
+ simpleOutRecTrack5
+ simpleOutRecTrack6
simpleOutputPath
simpleOutputBrowse
simpleNoSpace
diff --git a/UI/window-basic-main-outputs.cpp b/UI/window-basic-main-outputs.cpp
index e569d26ed..4cdeb94bd 100644
--- a/UI/window-basic-main-outputs.cpp
+++ b/UI/window-basic-main-outputs.cpp
@@ -438,6 +438,7 @@ struct SimpleOutput : BasicOutputHandler {
OBSEncoder audioRecording;
OBSEncoder audioArchive;
OBSEncoder videoRecording;
+ OBSEncoder audioTrack[MAX_AUDIO_MIXES];
string videoEncoder;
string videoQuality;
@@ -502,8 +503,6 @@ void SimpleOutput::LoadRecordingPreset_Lossless()
obs_data_set_string(settings, "video_encoder", "utvideo");
obs_data_set_string(settings, "audio_encoder", "pcm_s16le");
- int aMixes = 1;
- obs_output_set_mixers(fileOutput, aMixes);
obs_output_update(fileOutput, settings);
}
@@ -611,6 +610,25 @@ void SimpleOutput::LoadRecordingPreset()
if (!success)
throw "Failed to create audio recording encoder "
"(simple output)";
+ for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
+ char name[23];
+ if (strcmp(audio_encoder, "opus") == 0) {
+ snprintf(name, sizeof name,
+ "simple_opus_recording%d", i);
+ success = CreateSimpleOpusEncoder(
+ audioTrack[i], GetAudioBitrate(), name,
+ i);
+ } else {
+ snprintf(name, sizeof name,
+ "simple_aac_recording%d", i);
+ success = CreateSimpleAACEncoder(
+ audioTrack[i], GetAudioBitrate(), name,
+ i);
+ }
+ if (!success)
+ throw "Failed to create multi-track audio recording encoder "
+ "(simple output)";
+ }
}
}
@@ -813,7 +831,23 @@ void SimpleOutput::UpdateRecordingAudioSettings()
obs_data_set_int(settings, "bitrate", 192);
obs_data_set_string(settings, "rate_control", "CBR");
- obs_encoder_update(audioRecording, settings);
+ int tracks =
+ config_get_int(main->Config(), "SimpleOutput", "RecTracks");
+ const char *recFormat =
+ config_get_string(main->Config(), "SimpleOutput", "RecFormat");
+ const char *quality =
+ config_get_string(main->Config(), "SimpleOutput", "RecQuality");
+ bool flv = strcmp(recFormat, "flv") == 0;
+
+ if (flv || strcmp(quality, "Stream") == 0) {
+ obs_encoder_update(audioRecording, settings);
+ } else {
+ for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
+ if ((tracks & (1 << i)) != 0) {
+ obs_encoder_update(audioTrack[i], settings);
+ }
+ }
+ }
}
#define CROSS_DIST_CUTOFF 2000.0
@@ -987,6 +1021,11 @@ inline void SimpleOutput::SetupOutputs()
obs_encoder_set_video(videoStreaming, obs_get_video());
obs_encoder_set_audio(audioStreaming, obs_get_audio());
obs_encoder_set_audio(audioArchive, obs_get_audio());
+ int tracks =
+ config_get_int(main->Config(), "SimpleOutput", "RecTracks");
+ const char *recFormat =
+ config_get_string(main->Config(), "SimpleOutput", "RecFormat");
+ bool flv = strcmp(recFormat, "flv") == 0;
if (usingRecordingPreset) {
if (ffmpegOutput) {
@@ -994,8 +1033,21 @@ inline void SimpleOutput::SetupOutputs()
obs_get_audio());
} else {
obs_encoder_set_video(videoRecording, obs_get_video());
- obs_encoder_set_audio(audioRecording, obs_get_audio());
+ if (flv) {
+ obs_encoder_set_audio(audioRecording,
+ obs_get_audio());
+ } else {
+ for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
+ if ((tracks & (1 << i)) != 0) {
+ obs_encoder_set_audio(
+ audioTrack[i],
+ obs_get_audio());
+ }
+ }
+ }
}
+ } else {
+ obs_encoder_set_audio(audioRecording, obs_get_audio());
}
}
@@ -1175,6 +1227,16 @@ bool SimpleOutput::StartStreaming(obs_service_t *service)
void SimpleOutput::UpdateRecording()
{
+ const char *recFormat =
+ config_get_string(main->Config(), "SimpleOutput", "RecFormat");
+ bool flv = strcmp(recFormat, "flv") == 0;
+ int tracks =
+ config_get_int(main->Config(), "SimpleOutput", "RecTracks");
+ int idx = 0;
+ int idx2 = 0;
+ const char *quality =
+ config_get_string(main->Config(), "SimpleOutput", "RecQuality");
+
if (replayBufferActive || recordingActive)
return;
@@ -1190,11 +1252,33 @@ void SimpleOutput::UpdateRecording()
if (!ffmpegOutput) {
obs_output_set_video_encoder(fileOutput, videoRecording);
- obs_output_set_audio_encoder(fileOutput, audioRecording, 0);
+ if (flv || strcmp(quality, "Stream") == 0) {
+ obs_output_set_audio_encoder(fileOutput, audioRecording,
+ 0);
+ } else {
+ for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
+ if ((tracks & (1 << i)) != 0) {
+ obs_output_set_audio_encoder(
+ fileOutput, audioTrack[i],
+ idx++);
+ }
+ }
+ }
}
if (replayBuffer) {
obs_output_set_video_encoder(replayBuffer, videoRecording);
- obs_output_set_audio_encoder(replayBuffer, audioRecording, 0);
+ if (flv || strcmp(quality, "Stream") == 0) {
+ obs_output_set_audio_encoder(replayBuffer,
+ audioRecording, 0);
+ } else {
+ for (int i = 0; i < MAX_AUDIO_MIXES; i++) {
+ if ((tracks & (1 << i)) != 0) {
+ obs_output_set_audio_encoder(
+ replayBuffer, audioTrack[i],
+ idx2++);
+ }
+ }
+ }
}
recordingConfigured = true;
@@ -1222,6 +1306,11 @@ bool SimpleOutput::ConfigureRecording(bool updateReplayBuffer)
config_get_int(main->Config(), "SimpleOutput", "RecRBTime");
int rbSize =
config_get_int(main->Config(), "SimpleOutput", "RecRBSize");
+ int tracks =
+ config_get_int(main->Config(), "SimpleOutput", "RecTracks");
+ const char *recFormat =
+ config_get_string(main->Config(), "SimpleOutput", "RecFormat");
+ bool flv = strcmp(recFormat, "flv") == 0;
bool is_fragmented = strcmp(format, "fmp4") == 0 ||
strcmp(format, "fmov") == 0;
@@ -1253,6 +1342,8 @@ bool SimpleOutput::ConfigureRecording(bool updateReplayBuffer)
f.c_str(), ffmpegOutput);
obs_data_set_string(settings, ffmpegOutput ? "url" : "path",
strPath.c_str());
+ if (ffmpegOutput)
+ obs_output_set_mixers(fileOutput, tracks);
}
// Use fragmented MOV/MP4 if user has not already specified custom movflags
diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp
index 7cc94006c..d7ae3e94f 100644
--- a/UI/window-basic-main.cpp
+++ b/UI/window-basic-main.cpp
@@ -1534,6 +1534,8 @@ bool OBSBasic::InitBasicConfigDefaults()
"StreamAudioEncoder", "aac");
config_set_default_string(basicConfig, "SimpleOutput",
"RecAudioEncoder", "aac");
+ config_set_default_uint(basicConfig, "SimpleOutput", "RecTracks",
+ (1 << 0));
config_set_default_bool(basicConfig, "AdvOut", "ApplyServiceSettings",
true);
diff --git a/UI/window-basic-settings.cpp b/UI/window-basic-settings.cpp
index 6114e703b..a50bc39ec 100644
--- a/UI/window-basic-settings.cpp
+++ b/UI/window-basic-settings.cpp
@@ -493,6 +493,12 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
HookWidget(ui->simpleOutRecQuality, COMBO_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->simpleOutRecEncoder, COMBO_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->simpleOutRecAEncoder, COMBO_CHANGED, OUTPUTS_CHANGED);
+ HookWidget(ui->simpleOutRecTrack1, CHECK_CHANGED, OUTPUTS_CHANGED);
+ HookWidget(ui->simpleOutRecTrack2, CHECK_CHANGED, OUTPUTS_CHANGED);
+ HookWidget(ui->simpleOutRecTrack3, CHECK_CHANGED, OUTPUTS_CHANGED);
+ HookWidget(ui->simpleOutRecTrack4, CHECK_CHANGED, OUTPUTS_CHANGED);
+ HookWidget(ui->simpleOutRecTrack5, CHECK_CHANGED, OUTPUTS_CHANGED);
+ HookWidget(ui->simpleOutRecTrack6, CHECK_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->simpleOutMuxCustom, EDIT_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->simpleReplayBuf, CHECK_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->simpleRBSecMax, SCROLL_CHANGED, OUTPUTS_CHANGED);
@@ -1946,6 +1952,15 @@ void OBSBasicSettings::LoadSimpleOutputSettings()
config_get_int(main->Config(), "SimpleOutput", "RecRBTime");
int rbSize =
config_get_int(main->Config(), "SimpleOutput", "RecRBSize");
+ int tracks =
+ config_get_int(main->Config(), "SimpleOutput", "RecTracks");
+
+ ui->simpleOutRecTrack1->setChecked(tracks & (1 << 0));
+ ui->simpleOutRecTrack2->setChecked(tracks & (1 << 1));
+ ui->simpleOutRecTrack3->setChecked(tracks & (1 << 2));
+ ui->simpleOutRecTrack4->setChecked(tracks & (1 << 3));
+ ui->simpleOutRecTrack5->setChecked(tracks & (1 << 4));
+ ui->simpleOutRecTrack6->setChecked(tracks & (1 << 5));
curPreset = preset;
curQSVPreset = qsvPreset;
@@ -3837,6 +3852,14 @@ void OBSBasicSettings::SaveOutputSettings()
SaveCheckBox(ui->simpleReplayBuf, "SimpleOutput", "RecRB");
SaveSpinBox(ui->simpleRBSecMax, "SimpleOutput", "RecRBTime");
SaveSpinBox(ui->simpleRBMegsMax, "SimpleOutput", "RecRBSize");
+ config_set_int(
+ main->Config(), "SimpleOutput", "RecTracks",
+ (ui->simpleOutRecTrack1->isChecked() ? (1 << 0) : 0) |
+ (ui->simpleOutRecTrack2->isChecked() ? (1 << 1) : 0) |
+ (ui->simpleOutRecTrack3->isChecked() ? (1 << 2) : 0) |
+ (ui->simpleOutRecTrack4->isChecked() ? (1 << 3) : 0) |
+ (ui->simpleOutRecTrack5->isChecked() ? (1 << 4) : 0) |
+ (ui->simpleOutRecTrack6->isChecked() ? (1 << 5) : 0));
curAdvStreamEncoder = GetComboData(ui->advOutEncoder);
@@ -5433,12 +5456,31 @@ void OBSBasicSettings::SimpleReplayBufferChanged()
bool replayBufferEnabled = ui->simpleReplayBuf->isChecked();
bool lossless = qual == "Lossless";
bool streamQuality = qual == "Stream";
+ int abitrate = 0;
ui->simpleRBMegsMax->setVisible(!streamQuality);
ui->simpleRBMegsMaxLabel->setVisible(!streamQuality);
+ if (ui->simpleOutRecFormat->currentText().compare("flv") == 0 ||
+ streamQuality) {
+ abitrate = ui->simpleOutputABitrate->currentText().toInt();
+ } else {
+ int delta = ui->simpleOutputABitrate->currentText().toInt();
+ if (ui->simpleOutRecTrack1->isChecked())
+ abitrate += delta;
+ if (ui->simpleOutRecTrack2->isChecked())
+ abitrate += delta;
+ if (ui->simpleOutRecTrack3->isChecked())
+ abitrate += delta;
+ if (ui->simpleOutRecTrack4->isChecked())
+ abitrate += delta;
+ if (ui->simpleOutRecTrack5->isChecked())
+ abitrate += delta;
+ if (ui->simpleOutRecTrack6->isChecked())
+ abitrate += delta;
+ }
+
int vbitrate = ui->simpleOutputVBitrate->value();
- int abitrate = ui->simpleOutputABitrate->currentText().toInt();
int seconds = ui->simpleRBSecMax->value();
// Set maximum to 75% of installed memory
@@ -5790,6 +5832,22 @@ void OBSBasicSettings::SimpleRecordingEncoderChanged()
QTStr("Basic.Settings.Advanced.AutoRemux").arg("mp4"));
}
+ if (qual == "Stream") {
+ ui->simpleRecTrackWidget->setCurrentWidget(ui->simpleFlvTracks);
+ ui->simpleFlvTracks->setEnabled(false);
+ } else if (qual == "Lossless") {
+ ui->simpleRecTrackWidget->setCurrentWidget(ui->simpleRecTracks);
+ } else {
+ if (format == "flv") {
+ ui->simpleRecTrackWidget->setCurrentWidget(
+ ui->simpleFlvTracks);
+ ui->simpleFlvTracks->setEnabled(false);
+ } else {
+ ui->simpleRecTrackWidget->setCurrentWidget(
+ ui->simpleRecTracks);
+ }
+ }
+
if (warning.isEmpty())
return;