diff --git a/frontend/utility/AdvancedOutput.cpp b/frontend/utility/AdvancedOutput.cpp index aff3ad623..d1d4d28e3 100644 --- a/frontend/utility/AdvancedOutput.cpp +++ b/frontend/utility/AdvancedOutput.cpp @@ -700,12 +700,6 @@ bool AdvancedOutput::StartStreaming(obs_service_t *service) #endif bool enableDynBitrate = config_get_bool(main->Config(), "Output", "DynamicBitrate"); - if (multitrackVideo && multitrackVideoActive && - !multitrackVideo->HandleIncompatibleSettings(main, main->Config(), service, enableDynBitrate)) { - multitrackVideoActive = false; - return false; - } - bool is_rtmp = false; obs_service_t *service_obj = main->GetService(); const char *protocol = obs_service_get_protocol(service_obj); diff --git a/frontend/utility/MultitrackVideoOutput.cpp b/frontend/utility/MultitrackVideoOutput.cpp index bc8823ed3..0410ff19e 100644 --- a/frontend/utility/MultitrackVideoOutput.cpp +++ b/frontend/utility/MultitrackVideoOutput.cpp @@ -29,6 +29,8 @@ static const char *av1_main = "Main"; // Maximum reconnect attempts with an invalid key error before giving up (roughly 30 seconds with default start value) static constexpr uint8_t MAX_RECONNECT_ATTEMPTS = 5; +using json = nlohmann::json; + Qt::ConnectionType BlockingConnectionTypeFor(QObject *object) { return object->thread() == QThread::currentThread() ? Qt::DirectConnection : Qt::BlockingQueuedConnection; @@ -574,85 +576,10 @@ void MultitrackVideoOutput::StopStreaming() obs_output_stop(dump_output); } -bool MultitrackVideoOutput::HandleIncompatibleSettings(QWidget *parent, config_t *config, obs_service_t *service, - bool &enableDynBitrate) -{ - QString incompatible_settings; - QString where_to_disable; - QString incompatible_settings_list; - - size_t num = 1; - - auto check_setting = [&](bool setting, const char *name, const char *section) { - if (!setting) - return; - - incompatible_settings += QString(" %1. %2\n").arg(num).arg(QTStr(name)); - - where_to_disable += QString(" %1. [%2 → %3 → %4]\n") - .arg(num) - .arg(QTStr("Settings")) - .arg(QTStr("Basic.Settings.Advanced")) - .arg(QTStr(section)); - - incompatible_settings_list += QString("%1, ").arg(name); - - num += 1; - }; - - check_setting(enableDynBitrate, "Basic.Settings.Output.DynamicBitrate.Beta", "Basic.Settings.Advanced.Network"); - - if (incompatible_settings.isEmpty()) - return true; - - OBSDataAutoRelease service_settings = obs_service_get_settings(service); - - QMessageBox mb(parent); - mb.setIcon(QMessageBox::Critical); - mb.setWindowTitle(QTStr("MultitrackVideo.IncompatibleSettings.Title")); - mb.setText(QString(QTStr("MultitrackVideo.IncompatibleSettings.Text")) - .arg(obs_data_get_string(service_settings, "multitrack_video_name")) - .arg(incompatible_settings) - .arg(where_to_disable)); - auto this_stream = mb.addButton(QTStr("MultitrackVideo.IncompatibleSettings.DisableAndStartStreaming"), - QMessageBox::AcceptRole); - auto all_streams = mb.addButton(QString(QTStr("MultitrackVideo.IncompatibleSettings.UpdateAndStartStreaming")), - QMessageBox::AcceptRole); - mb.setStandardButtons(QMessageBox::StandardButton::Cancel); - - mb.exec(); - - const char *action = "cancel"; - if (mb.clickedButton() == this_stream) { - action = "DisableAndStartStreaming"; - } else if (mb.clickedButton() == all_streams) { - action = "UpdateAndStartStreaming"; - } - - blog(LOG_INFO, - "MultitrackVideoOutput: attempted to start stream with incompatible" - "settings (%s); action taken: %s", - incompatible_settings_list.toUtf8().constData(), action); - - if (mb.clickedButton() == this_stream || mb.clickedButton() == all_streams) { - enableDynBitrate = false; - - if (mb.clickedButton() == all_streams) { - config_set_bool(config, "Output", "DynamicBitrate", false); - } - - return true; - } - - MultitrackVideoOutput::ReleaseOnMainThread(take_current()); - MultitrackVideoOutput::ReleaseOnMainThread(take_current_stream_dump()); - - return false; -} - static bool create_video_encoders(const GoLiveApi::Config &go_live_config, std::shared_ptr &video_encoder_group, obs_output_t *output, - obs_output_t *recording_output, const std::vector &canvases) + obs_output_t *recording_output, json &bitrate_interpolation_array, + const std::vector &canvases) { DStr video_encoder_name_buffer; if (go_live_config.encoder_configurations.empty()) { @@ -684,6 +611,12 @@ static bool create_video_encoders(const GoLiveApi::Config &go_live_config, obs_output_set_video_encoder2(output, encoder, i); if (recording_output) obs_output_set_video_encoder2(recording_output, encoder, i); + + auto &data = go_live_config.encoder_configurations[i].bitrate_interpolation_points; + if (data.has_value()) + bitrate_interpolation_array.push_back(*data); + else + bitrate_interpolation_array.push_back(json::array()); } video_encoder_group = encoder_group; @@ -843,9 +776,15 @@ static OBSOutputs SetupOBSOutput(QWidget *parent, const QString &multitrack_vide if (dump_stream_to_file_config) recording_output = create_recording_output(dump_stream_to_file_config); - if (!create_video_encoders(go_live_config, video_encoder_group, output, recording_output, canvases)) + json bitrate_interpolation_array = json::array(); + if (!create_video_encoders(go_live_config, video_encoder_group, output, recording_output, + bitrate_interpolation_array, canvases)) return {nullptr, nullptr}; + OBSDataAutoRelease settings = obs_output_get_settings(output); + obs_data_set_string(settings, "interpolation_table_data", bitrate_interpolation_array.dump().c_str()); + obs_output_update(output, settings); + std::vector requested_speaker_layouts; speaker_layout current_layout = SPEAKERS_UNKNOWN; create_audio_encoders(go_live_config, audio_encoders, output, recording_output, audio_encoder_id, diff --git a/frontend/utility/MultitrackVideoOutput.hpp b/frontend/utility/MultitrackVideoOutput.hpp index 3bcb8cf6b..2d616c4b8 100644 --- a/frontend/utility/MultitrackVideoOutput.hpp +++ b/frontend/utility/MultitrackVideoOutput.hpp @@ -32,8 +32,6 @@ public: signal_handler_t *StreamingSignalHandler(); void StartedStreaming(); void StopStreaming(); - bool HandleIncompatibleSettings(QWidget *parent, config_t *config, obs_service_t *service, - bool &enableDynBitrate); OBSOutputAutoRelease StreamingOutput() { diff --git a/frontend/utility/SimpleOutput.cpp b/frontend/utility/SimpleOutput.cpp index bdda70d5b..9e8da9204 100644 --- a/frontend/utility/SimpleOutput.cpp +++ b/frontend/utility/SimpleOutput.cpp @@ -695,12 +695,6 @@ bool SimpleOutput::StartStreaming(obs_service_t *service) #endif bool enableDynBitrate = config_get_bool(main->Config(), "Output", "DynamicBitrate"); - if (multitrackVideo && multitrackVideoActive && - !multitrackVideo->HandleIncompatibleSettings(main, main->Config(), service, enableDynBitrate)) { - multitrackVideoActive = false; - return false; - } - OBSDataAutoRelease settings = obs_data_create(); obs_data_set_string(settings, "bind_ip", bindIP); obs_data_set_string(settings, "ip_family", ipFamily); diff --git a/frontend/utility/models/multitrack-video.hpp b/frontend/utility/models/multitrack-video.hpp index 0aa1cae65..cb6d49dcb 100644 --- a/frontend/utility/models/multitrack-video.hpp +++ b/frontend/utility/models/multitrack-video.hpp @@ -249,11 +249,13 @@ struct VideoEncoderConfiguration { optional colorspace; optional range; optional format; + optional bitrate_interpolation_points; json settings; uint32_t canvas_index; NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(VideoEncoderConfiguration, type, width, height, framerate, - gpu_scale_type, colorspace, range, format, settings, canvas_index) + gpu_scale_type, colorspace, range, format, + bitrate_interpolation_points, settings, canvas_index) }; struct AudioEncoderConfiguration {