Skip to content

Commit af77628

Browse files
Alex LuccisanoRytoEX
authored andcommitted
frontend: Fix null settings and DBR for custom configs
When using custom RTMP output with a JSON config that omits encoder settings, settings.dump() produces "null" which obs_data_create_from_json cannot parse. Fall back to obs_data_create() for null/non-object settings so encoders use their defaults. Additionally, when bitrate_interpolation_points is absent, the code unconditionally set interpolation_table_data as empty arrays. This caused build_dbr_interpolation_table to wipe the default linear table, leaving DBR enabled but unable to adjust bitrates during congestion. Only set the interpolation data when all encoders provide it, otherwise fall back to the default linear 0-to-max interpolation.
1 parent 83ed914 commit af77628

1 file changed

Lines changed: 33 additions & 5 deletions

File tree

frontend/utility/MultitrackVideoOutput.cpp

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <QUrl>
1717
#include <QUrlQuery>
1818

19+
#include <algorithm>
1920
#include <cinttypes>
2021

2122
// Codec profile strings
@@ -238,7 +239,14 @@ static OBSEncoderAutoRelease create_video_encoder(DStr &name_buffer, size_t enco
238239

239240
dstr_printf(name_buffer, "multitrack video video encoder %zu", encoder_index);
240241

241-
OBSDataAutoRelease encoder_settings = obs_data_create_from_json(encoder_config.settings.dump().c_str());
242+
// settings.dump() produces "null" when the config omits encoder settings, which
243+
// obs_data_create_from_json cannot parse. Fall back to empty settings so the encoder uses its defaults.
244+
OBSDataAutoRelease encoder_settings =
245+
encoder_config.settings.is_object() ? obs_data_create_from_json(encoder_config.settings.dump().c_str())
246+
: obs_data_create();
247+
if (!encoder_config.settings.is_object()) {
248+
blog(LOG_INFO, "Encoder %zu has no settings, using defaults", encoder_index);
249+
}
242250

243251
/* VAAPI-based encoders unfortunately use an integer for "profile". Until a string-based "profile" can be used with
244252
* VAAPI, find the corresponding integer value and update the settings with an integer-based "profile".
@@ -613,10 +621,11 @@ static bool create_video_encoders(const GoLiveApi::Config &go_live_config,
613621
obs_output_set_video_encoder2(recording_output, encoder, i);
614622

615623
auto &data = go_live_config.encoder_configurations[i].bitrate_interpolation_points;
616-
if (data.has_value())
624+
if (data.has_value()) {
617625
bitrate_interpolation_array.push_back(*data);
618-
else
626+
} else {
619627
bitrate_interpolation_array.push_back(json::array());
628+
}
620629
}
621630

622631
video_encoder_group = encoder_group;
@@ -675,7 +684,15 @@ static void create_audio_encoders(const GoLiveApi::Config &go_live_config,
675684

676685
for (size_t i = 0; i < configs.size(); i++) {
677686
dstr_printf(encoder_name_buffer, "%s %zu", name_prefix, i);
678-
OBSDataAutoRelease settings = obs_data_create_from_json(configs[i].settings.dump().c_str());
687+
// settings.dump() produces "null" when the config omits encoder settings,
688+
// which obs_data_create_from_json cannot parse. Fall back to empty settings.
689+
OBSDataAutoRelease settings =
690+
configs[i].settings.is_object()
691+
? obs_data_create_from_json(configs[i].settings.dump().c_str())
692+
: obs_data_create();
693+
if (!configs[i].settings.is_object()) {
694+
blog(LOG_INFO, "Audio encoder %zu has no settings, using defaults", i);
695+
}
679696
OBSEncoderAutoRelease audio_encoder =
680697
create_audio_encoder(encoder_name_buffer->array, audio_encoder_id, settings, mixer_idx);
681698

@@ -782,7 +799,18 @@ static OBSOutputs SetupOBSOutput(QWidget *parent, const QString &multitrack_vide
782799
return {nullptr, nullptr};
783800

784801
OBSDataAutoRelease settings = obs_output_get_settings(output);
785-
obs_data_set_string(settings, "interpolation_table_data", bitrate_interpolation_array.dump().c_str());
802+
// Only set interpolation_table_data if every encoder has interpolation points. Partial data would
803+
// fail validation in the output plugin and disable DBR. Omitting it lets the output use its default
804+
// linear interpolation (proportional scaling from 0 to max bitrate).
805+
bool has_interpolation_data = std::all_of(bitrate_interpolation_array.begin(),
806+
bitrate_interpolation_array.end(),
807+
[](const json &arr) { return !arr.empty(); });
808+
if (has_interpolation_data) {
809+
obs_data_set_string(settings, "interpolation_table_data", bitrate_interpolation_array.dump().c_str());
810+
} else {
811+
blog(LOG_INFO,
812+
"Interpolation data missing for one or more encoders, using default linear interpolation");
813+
}
786814
obs_output_update(output, settings);
787815

788816
std::vector<speaker_layout> requested_speaker_layouts;

0 commit comments

Comments
 (0)