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;