mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-09-01 15:49:51 +08:00
frontend: Fix multitrack custom config handling
Custom configuration for multitrack-enabled services is only supposed to be available for the "rtmp_custom" service type, as that's also the condition for the corresponding text input to become visible in the settings dialog. When a user switches their desired service from the custom service back to another service that also supports multitrack, the custom service configuration is still present and will be applied even though it should only be effective for the custom service. This change makes the simple decision to ignore any available custom multitrack configuration if the service is not "rtmp_custom" and requires an "auto_config_url" to be available in that case. Otherwise the "rtmp_custom" service requires an "custom_config" to be available. That way the implementation reflects the behavior of the settings dialog and will not lead to the present unexpected behavior, including: * The custom configuration is "merged" with the config ID provided via the "auto_config_url". * A non-custom service might fail to configure because the custom config is applied and might be missing required fields. * A non-custom service might succeed to configure because the custom config is applied and has all required fields, but the service was meant for an entirely different service. Additionally the unused "MultitrackVideoDeveloperModeEnabled" function was removed. For simplicity's sake, all legacy code paths that allowed interference or custom overrides with the service configuration for established services are removed. If such functionality is still desired, it needs to be reimplemented in a service-agnostic way, taking the possibility of other multitrack- capable services into account.
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cinttypes>
|
||||
#include <string_view>
|
||||
|
||||
// Codec profile strings
|
||||
static const char *h264_main = "Main";
|
||||
@@ -27,6 +28,8 @@ static const char *hevc_main = "Main";
|
||||
static const char *hevc_main10 = "Main 10";
|
||||
static const char *av1_main = "Main";
|
||||
|
||||
constexpr std::string_view kCustomRtmpIdentifier{"rtmp_custom"};
|
||||
|
||||
// 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;
|
||||
|
||||
@@ -37,20 +40,6 @@ Qt::ConnectionType BlockingConnectionTypeFor(QObject *object)
|
||||
return object->thread() == QThread::currentThread() ? Qt::DirectConnection : Qt::BlockingQueuedConnection;
|
||||
}
|
||||
|
||||
bool MultitrackVideoDeveloperModeEnabled()
|
||||
{
|
||||
static bool developer_mode = [] {
|
||||
auto args = qApp->arguments();
|
||||
for (const auto &arg : args) {
|
||||
if (arg == "--enable-multitrack-video-dev") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}();
|
||||
return developer_mode;
|
||||
}
|
||||
|
||||
static OBSServiceAutoRelease create_service(const GoLiveApi::Config &go_live_config,
|
||||
const std::optional<std::string> &rtmp_url, const QString &in_stream_key,
|
||||
std::optional<bool> use_rtmps)
|
||||
@@ -420,49 +409,53 @@ void MultitrackVideoOutput::PrepareStreaming(
|
||||
rtmp_url.has_value() ? rtmp_url->c_str() : "",
|
||||
vod_track_info_storage->array ? vod_track_info_storage->array : "No", canvasNames.c_str());
|
||||
|
||||
const bool custom_config_only = auto_config_url.isEmpty() && custom_config.has_value() &&
|
||||
strcmp(obs_service_get_id(service), "rtmp_custom") == 0;
|
||||
// This will crash if serviceId is a nullptr. Deliberately unhandled because that would constitute a critical
|
||||
// application state error.
|
||||
const char *serviceId = obs_service_get_id(service);
|
||||
std::string_view serviceIdString{serviceId};
|
||||
|
||||
if (!custom_config_only) {
|
||||
auto go_live_post = constructGoLivePost(stream_key, maximum_aggregate_bitrate, maximum_video_tracks,
|
||||
vod_track_mixer.has_value(), canvases);
|
||||
bool isCustomRtmpService = (serviceIdString == kCustomRtmpIdentifier);
|
||||
bool hasAutoConfigUrl = !auto_config_url.isEmpty();
|
||||
bool hasCustomConfig = custom_config.has_value();
|
||||
|
||||
go_live_config = DownloadGoLiveConfig(parent, auto_config_url, go_live_post, multitrack_video_name);
|
||||
}
|
||||
if (!isCustomRtmpService) {
|
||||
if (hasAutoConfigUrl) {
|
||||
auto go_live_post = constructGoLivePost(stream_key, maximum_aggregate_bitrate,
|
||||
maximum_video_tracks, vod_track_mixer.has_value(),
|
||||
canvases);
|
||||
|
||||
if (custom_config.has_value()) {
|
||||
GoLiveApi::Config parsed_custom;
|
||||
try {
|
||||
parsed_custom = nlohmann::json::parse(*custom_config);
|
||||
} catch (const nlohmann::json::exception &exception) {
|
||||
blog(LOG_WARNING, "Failed to parse custom config: %s", exception.what());
|
||||
throw MultitrackVideoError::critical(QTStr("FailedToStartStream.InvalidCustomConfig"));
|
||||
go_live_config =
|
||||
DownloadGoLiveConfig(parent, auto_config_url, go_live_post, multitrack_video_name);
|
||||
|
||||
if (go_live_config) {
|
||||
blog(LOG_INFO, "Enhanced broadcasting config_id: '%s'",
|
||||
go_live_config->meta.config_id.c_str());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (hasCustomConfig) {
|
||||
GoLiveApi::Config parsed_custom;
|
||||
try {
|
||||
parsed_custom = nlohmann::json::parse(*custom_config);
|
||||
} catch (const nlohmann::json::exception &exception) {
|
||||
blog(LOG_WARNING, "Failed to parse custom config: %s", exception.what());
|
||||
throw MultitrackVideoError::critical(QTStr("FailedToStartStream.InvalidCustomConfig"));
|
||||
}
|
||||
|
||||
// copy unique ID from go live request
|
||||
if (go_live_config.has_value()) {
|
||||
parsed_custom.meta.config_id = go_live_config->meta.config_id;
|
||||
blog(LOG_INFO, "Using config_id from go live config with custom config: %s",
|
||||
parsed_custom.meta.config_id.c_str());
|
||||
nlohmann::json custom_data = parsed_custom;
|
||||
blog(LOG_INFO, "Using custom go live config: %s", custom_data.dump(4).c_str());
|
||||
|
||||
custom.emplace(std::move(parsed_custom));
|
||||
}
|
||||
|
||||
nlohmann::json custom_data = parsed_custom;
|
||||
blog(LOG_INFO, "Using custom go live config: %s", custom_data.dump(4).c_str());
|
||||
|
||||
custom.emplace(std::move(parsed_custom));
|
||||
}
|
||||
|
||||
if (go_live_config.has_value()) {
|
||||
blog(LOG_INFO, "Enhanced broadcasting config_id: '%s'", go_live_config->meta.config_id.c_str());
|
||||
}
|
||||
|
||||
if (!go_live_config && !custom) {
|
||||
if (!(go_live_config || custom)) {
|
||||
blog(LOG_ERROR, "MultitrackVideoOutput: no config set, this should never happen");
|
||||
throw MultitrackVideoError::warning(QTStr("FailedToStartStream.NoConfig"));
|
||||
throw MultitrackVideoError::warning(QTStr("FailedToStartStream.NoConfigSupplied"));
|
||||
}
|
||||
|
||||
const auto &output_config = custom ? *custom : *go_live_config;
|
||||
const auto &service_config = go_live_config ? *go_live_config : *custom;
|
||||
const auto &service_config = custom ? *custom : *go_live_config;
|
||||
|
||||
std::vector<OBSEncoderAutoRelease> audio_encoders;
|
||||
std::shared_ptr<obs_encoder_group_t> video_encoder_group;
|
||||
|
||||
@@ -18,8 +18,6 @@ void StreamStopHandler(void *arg, calldata_t *data);
|
||||
void RecordingStartHandler(void *arg, calldata_t *data);
|
||||
void RecordingStopHandler(void *arg, calldata_t *);
|
||||
|
||||
bool MultitrackVideoDeveloperModeEnabled();
|
||||
|
||||
struct MultitrackVideoOutput {
|
||||
public:
|
||||
void PrepareStreaming(QWidget *parent, const char *service_name, obs_service_t *service,
|
||||
|
||||
Reference in New Issue
Block a user