mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-08-29 02:03:03 +08:00
frontend: Allow selecting additional canvases for multitrack
This commit is contained in:
committed by
Ryan Foster
parent
8117c89b9a
commit
0552062390
@@ -994,6 +994,7 @@ Basic.Settings.Stream.MultitrackVideoStreamDumpEnable="Enable stream dump to FLV
|
||||
Basic.Settings.Stream.MultitrackVideoConfigOverride="Config Override (JSON)"
|
||||
Basic.Settings.Stream.MultitrackVideoConfigOverrideEnable="Enable Config Override"
|
||||
Basic.Settings.Stream.MultitrackVideoLabel="Multitrack Video"
|
||||
Basic.Settings.Stream.MultitrackVideoExtraCanvas="Additional Canvas"
|
||||
Basic.Settings.Stream.AdvancedOptions="Advanced Options"
|
||||
|
||||
# basic mode 'output' settings
|
||||
@@ -1576,6 +1577,7 @@ ConfigDownload.WarningMessageTitle="Warning"
|
||||
FailedToStartStream.MissingConfigURL="No config URL available for the current service"
|
||||
FailedToStartStream.NoCustomRTMPURLInSettings="Custom RTMP URL not specified"
|
||||
FailedToStartStream.InvalidCustomConfig="Invalid custom config"
|
||||
FailedToStartStream.MissingCanvas="A configured extra canvas is missing"
|
||||
FailedToStartStream.FailedToCreateMultitrackVideoService="Failed to create multitrack video service"
|
||||
FailedToStartStream.FailedToCreateMultitrackVideoOutput="Failed to create multitrack video RTMP output"
|
||||
FailedToStartStream.EncoderNotAvailable="NVENC not available.\n\nFailed to find encoder type '%1'"
|
||||
@@ -1589,6 +1591,7 @@ FailedToStartStream.WarningUnknownStatus="Received unknown status value '%1'"
|
||||
FailedToStartStream.WarningRetryNonMultitrackVideo="\n<br><br>\nDo you want to continue streaming without %1?"
|
||||
FailedToStartStream.WarningRetry="\n<br><br>\nDo you want to continue streaming?"
|
||||
FailedToStartStream.MissingEncoderConfigs="Go live config did not include encoder configurations"
|
||||
FailedToStartStream.InvalidEncoderConfig="Go live config included an invalid encoder configuration"
|
||||
FailedToStartStream.StatusMissingHTML="Go live request returned an unspecified error"
|
||||
FailedToStartStream.NoConfigSupplied="Missing config"
|
||||
MultitrackVideo.Info="%1 automatically optimizes your settings to encode and send multiple video qualities. Selecting this option will send %2 information about your computer and software setup."
|
||||
|
||||
@@ -1907,6 +1907,29 @@
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<spacer name="horizontalSpacer_30">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>170</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="enableMultitrackVideo">
|
||||
<property name="text">
|
||||
<string>Basic.Settings.Stream.EnableMultitrackVideo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="multitrackVideoMaximumAggregateBitrateLabel">
|
||||
<property name="text">
|
||||
@@ -1993,7 +2016,14 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="multitrackVideoAdditionalCanvas">
|
||||
<property name="placeholderText">
|
||||
<string>None</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<spacer name="horizontalSpacer_32">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
@@ -2009,28 +2039,28 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="multitrackVideoStreamDumpEnable">
|
||||
<property name="text">
|
||||
<string>Basic.Settings.Stream.MultitrackVideoStreamDumpEnable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<item row="5" column="1">
|
||||
<widget class="QCheckBox" name="multitrackVideoConfigOverrideEnable">
|
||||
<property name="text">
|
||||
<string>Basic.Settings.Stream.MultitrackVideoConfigOverrideEnable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="multitrackVideoConfigOverrideLabel">
|
||||
<property name="text">
|
||||
<string>Basic.Settings.Stream.MultitrackVideoConfigOverride</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="6" column="1">
|
||||
<widget class="QPlainTextEdit" name="multitrackVideoConfigOverride">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
@@ -2040,29 +2070,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="enableMultitrackVideo">
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="multitrackVideoAdditionalCanvasLabel">
|
||||
<property name="text">
|
||||
<string>Basic.Settings.Stream.EnableMultitrackVideo</string>
|
||||
<string>Basic.Settings.Stream.MultitrackVideoExtraCanvas</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<spacer name="horizontalSpacer_30">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>170</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
@@ -393,6 +393,7 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
|
||||
HookWidget(ui->multitrackVideoStreamDumpEnable, CHECK_CHANGED, STREAM1_CHANGED);
|
||||
HookWidget(ui->multitrackVideoConfigOverrideEnable, CHECK_CHANGED, STREAM1_CHANGED);
|
||||
HookWidget(ui->multitrackVideoConfigOverride, TEXT_CHANGED, STREAM1_CHANGED);
|
||||
HookWidget(ui->multitrackVideoAdditionalCanvas, COMBO_CHANGED, STREAM1_CHANGED);
|
||||
HookWidget(ui->outputMode, COMBO_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->simpleOutputPath, EDIT_CHANGED, OUTPUTS_CHANGED);
|
||||
HookWidget(ui->simpleNoSpace, CHECK_CHANGED, OUTPUTS_CHANGED);
|
||||
@@ -5621,6 +5622,7 @@ void OBSBasicSettings::UpdateMultitrackVideo()
|
||||
ui->enableMultitrackVideo->isChecked());
|
||||
ui->multitrackVideoMaximumVideoTracks->setEnabled(toggle_available && ui->enableMultitrackVideo->isChecked() &&
|
||||
!ui->multitrackVideoMaximumVideoTracksAuto->isChecked());
|
||||
ui->multitrackVideoAdditionalCanvas->setEnabled(toggle_available && ui->enableMultitrackVideo->isChecked());
|
||||
|
||||
ui->multitrackVideoStreamDumpEnable->setVisible(available && MultitrackVideoDeveloperModeEnabled());
|
||||
ui->multitrackVideoConfigOverrideEnable->setVisible(available && MultitrackVideoDeveloperModeEnabled());
|
||||
|
||||
@@ -170,6 +170,24 @@ void OBSBasicSettings::LoadStream1Settings()
|
||||
config_get_string(main->Config(), "Stream1", "MultitrackVideoConfigOverride"))
|
||||
.c_str());
|
||||
|
||||
ui->multitrackVideoAdditionalCanvas->clear();
|
||||
ui->multitrackVideoAdditionalCanvas->addItem(QTStr("None"));
|
||||
for (const auto &canvas : main->GetCanvases()) {
|
||||
if (obs_canvas_get_flags(canvas) & EPHEMERAL)
|
||||
continue;
|
||||
|
||||
ui->multitrackVideoAdditionalCanvas->addItem(obs_canvas_get_name(canvas), obs_canvas_get_uuid(canvas));
|
||||
}
|
||||
|
||||
if (config_has_user_value(main->Config(), "Stream1", "MultitrackExtraCanvas")) {
|
||||
/* Currently we only support one canvas, so the value will just be one UUID. */
|
||||
const std::string_view uuid = config_get_string(main->Config(), "Stream1", "MultitrackExtraCanvas");
|
||||
if (!uuid.empty()) {
|
||||
int idx = ui->multitrackVideoAdditionalCanvas->findData(uuid.data());
|
||||
ui->multitrackVideoAdditionalCanvas->setCurrentIndex(idx);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateServerList();
|
||||
|
||||
if (is_rtmp_common) {
|
||||
@@ -335,6 +353,7 @@ void OBSBasicSettings::SaveStream1Settings()
|
||||
SaveCheckBox(ui->multitrackVideoStreamDumpEnable, "Stream1", "MultitrackVideoStreamDumpEnabled");
|
||||
SaveCheckBox(ui->multitrackVideoConfigOverrideEnable, "Stream1", "MultitrackVideoConfigOverrideEnabled");
|
||||
SaveText(ui->multitrackVideoConfigOverride, "Stream1", "MultitrackVideoConfigOverride");
|
||||
SaveComboData(ui->multitrackVideoAdditionalCanvas, "Stream1", "MultitrackExtraCanvas");
|
||||
|
||||
if (oldMultitrackVideoSetting != ui->enableMultitrackVideo->isChecked())
|
||||
main->ResetOutputs();
|
||||
|
||||
@@ -457,6 +457,12 @@ std::shared_future<void> BasicOutputHandler::SetupMultitrackVideo(obs_service_t
|
||||
custom_config = DeserializeConfigText(
|
||||
config_get_string(main->Config(), "Stream1", "MultitrackVideoConfigOverride"));
|
||||
|
||||
std::optional<QString> extraCanvasUUID;
|
||||
const char *uuid = config_get_string(main->Config(), "Stream1", "MultitrackExtraCanvas");
|
||||
if (uuid && *uuid) {
|
||||
extraCanvasUUID = uuid;
|
||||
}
|
||||
|
||||
OBSDataAutoRelease settings = obs_service_get_settings(service);
|
||||
QString key = obs_data_get_string(settings, "key");
|
||||
|
||||
@@ -532,7 +538,8 @@ std::shared_future<void> BasicOutputHandler::SetupMultitrackVideo(obs_service_t
|
||||
multitrackVideo->PrepareStreaming(main, service_name.c_str(), service, custom_rtmp_url, key,
|
||||
audio_encoder_id.c_str(), maximum_aggregate_bitrate,
|
||||
maximum_video_tracks, custom_config, stream_dump_config,
|
||||
main_audio_mixer, vod_track_mixer, use_rtmps);
|
||||
main_audio_mixer, vod_track_mixer, use_rtmps,
|
||||
extraCanvasUUID);
|
||||
} catch (const MultitrackVideoError &error_) {
|
||||
error.emplace(error_);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
GoLiveApi::PostData constructGoLivePost(QString streamKey, const std::optional<uint64_t> &maximum_aggregate_bitrate,
|
||||
const std::optional<uint32_t> &maximum_video_tracks, bool vod_track_enabled)
|
||||
const std::optional<uint32_t> &maximum_video_tracks, bool vod_track_enabled,
|
||||
const std::vector<OBSCanvasAutoRelease> &canvases)
|
||||
{
|
||||
GoLiveApi::PostData post_data{};
|
||||
post_data.service = "IVS";
|
||||
@@ -49,13 +50,17 @@ GoLiveApi::PostData constructGoLivePost(QString streamKey, const std::optional<u
|
||||
preferences.vod_track_audio = vod_track_enabled;
|
||||
|
||||
obs_video_info ovi;
|
||||
if (obs_get_video_info(&ovi)) {
|
||||
if (obs_get_video_info(&ovi))
|
||||
preferences.composition_gpu_index = ovi.adapter;
|
||||
preferences.canvases.emplace_back(GoLiveApi::Canvas{ovi.output_width,
|
||||
ovi.output_height,
|
||||
ovi.base_width,
|
||||
ovi.base_height,
|
||||
{ovi.fps_num, ovi.fps_den}});
|
||||
|
||||
for (const auto &canvas : canvases) {
|
||||
if (obs_canvas_get_video_info(canvas, &ovi)) {
|
||||
preferences.canvases.emplace_back(GoLiveApi::Canvas{ovi.output_width,
|
||||
ovi.output_height,
|
||||
ovi.base_width,
|
||||
ovi.base_height,
|
||||
{ovi.fps_num, ovi.fps_den}});
|
||||
}
|
||||
}
|
||||
|
||||
obs_audio_info2 oai2;
|
||||
|
||||
@@ -9,4 +9,5 @@
|
||||
#include <optional>
|
||||
|
||||
GoLiveApi::PostData constructGoLivePost(QString streamKey, const std::optional<uint64_t> &maximum_aggregate_bitrate,
|
||||
const std::optional<uint32_t> &maximum_video_tracks, bool vod_track_enabled);
|
||||
const std::optional<uint32_t> &maximum_video_tracks, bool vod_track_enabled,
|
||||
const std::vector<OBSCanvasAutoRelease> &canvases);
|
||||
|
||||
@@ -222,7 +222,8 @@ static bool encoder_available(const char *type)
|
||||
}
|
||||
|
||||
static OBSEncoderAutoRelease create_video_encoder(DStr &name_buffer, size_t encoder_index,
|
||||
const GoLiveApi::VideoEncoderConfiguration &encoder_config)
|
||||
const GoLiveApi::VideoEncoderConfiguration &encoder_config,
|
||||
const OBSCanvasAutoRelease &canvas)
|
||||
{
|
||||
auto encoder_type = encoder_config.type.c_str();
|
||||
if (!encoder_available(encoder_type)) {
|
||||
@@ -292,10 +293,10 @@ static OBSEncoderAutoRelease create_video_encoder(DStr &name_buffer, size_t enco
|
||||
throw MultitrackVideoError::warning(
|
||||
QTStr("FailedToStartStream.FailedToCreateVideoEncoder").arg(name_buffer->array, encoder_type));
|
||||
}
|
||||
obs_encoder_set_video(video_encoder, obs_get_video());
|
||||
obs_encoder_set_video(video_encoder, obs_canvas_get_video(canvas));
|
||||
|
||||
obs_video_info ovi;
|
||||
if (!obs_get_video_info(&ovi)) {
|
||||
if (!obs_canvas_get_video_info(canvas, &ovi)) {
|
||||
blog(LOG_WARNING, "Failed to get obs_video_info while creating encoder %zu", encoder_index);
|
||||
throw MultitrackVideoError::warning(
|
||||
QTStr("FailedToStartStream.FailedToGetOBSVideoInfo").arg(name_buffer->array, encoder_type));
|
||||
@@ -329,18 +330,17 @@ static OBSOutputs SetupOBSOutput(QWidget *parent, const QString &multitrack_vide
|
||||
std::vector<OBSEncoderAutoRelease> &audio_encoders,
|
||||
std::shared_ptr<obs_encoder_group_t> &video_encoder_group,
|
||||
const char *audio_encoder_id, size_t main_audio_mixer,
|
||||
std::optional<size_t> vod_track_mixer);
|
||||
std::optional<size_t> vod_track_mixer,
|
||||
const std::vector<OBSCanvasAutoRelease> &canvases);
|
||||
static void SetupSignalHandlers(bool recording, MultitrackVideoOutput *self, obs_output_t *output, OBSSignal &start,
|
||||
OBSSignal &stop);
|
||||
|
||||
void MultitrackVideoOutput::PrepareStreaming(QWidget *parent, const char *service_name, obs_service_t *service,
|
||||
const std::optional<std::string> &rtmp_url, const QString &stream_key,
|
||||
const char *audio_encoder_id,
|
||||
std::optional<uint32_t> maximum_aggregate_bitrate,
|
||||
std::optional<uint32_t> maximum_video_tracks,
|
||||
std::optional<std::string> custom_config,
|
||||
obs_data_t *dump_stream_to_file_config, size_t main_audio_mixer,
|
||||
std::optional<size_t> vod_track_mixer, std::optional<bool> use_rtmps)
|
||||
void MultitrackVideoOutput::PrepareStreaming(
|
||||
QWidget *parent, const char *service_name, obs_service_t *service, const std::optional<std::string> &rtmp_url,
|
||||
const QString &stream_key, const char *audio_encoder_id, std::optional<uint32_t> maximum_aggregate_bitrate,
|
||||
std::optional<uint32_t> maximum_video_tracks, std::optional<std::string> custom_config,
|
||||
obs_data_t *dump_stream_to_file_config, size_t main_audio_mixer, std::optional<size_t> vod_track_mixer,
|
||||
std::optional<bool> use_rtmps, std::optional<QString> extra_canvas)
|
||||
{
|
||||
{
|
||||
const std::lock_guard<std::mutex> current_lock{current_mutex};
|
||||
@@ -366,6 +366,25 @@ void MultitrackVideoOutput::PrepareStreaming(QWidget *parent, const char *servic
|
||||
|
||||
auto auto_config_url_data = auto_config_url.toUtf8();
|
||||
|
||||
std::vector<OBSCanvasAutoRelease> canvases;
|
||||
|
||||
canvases.emplace_back(obs_get_main_canvas());
|
||||
if (extra_canvas) {
|
||||
obs_canvas_t *canvas = obs_get_canvas_by_uuid(extra_canvas->toUtf8().constData());
|
||||
if (!canvas) {
|
||||
throw MultitrackVideoError::critical(QTStr("FailedToStartStream.MissingCanvas"));
|
||||
}
|
||||
canvases.emplace_back(canvas);
|
||||
}
|
||||
|
||||
std::string canvasNames;
|
||||
for (const auto &canvas : canvases) {
|
||||
if (!canvasNames.empty())
|
||||
canvasNames += ", ";
|
||||
|
||||
canvasNames += obs_canvas_get_name(canvas);
|
||||
}
|
||||
|
||||
DStr vod_track_info_storage;
|
||||
if (vod_track_mixer.has_value())
|
||||
dstr_printf(vod_track_info_storage, "Yes (mixer: %zu)", vod_track_mixer.value());
|
||||
@@ -379,13 +398,14 @@ void MultitrackVideoOutput::PrepareStreaming(QWidget *parent, const char *servic
|
||||
" max aggregate bitrate: %s (%" PRIu32 ")\n"
|
||||
" max video tracks: %s (%" PRIu32 ")\n"
|
||||
" custom rtmp url: %s ('%s')\n"
|
||||
" vod track: %s",
|
||||
" vod track: %s\n"
|
||||
" canvases: %s",
|
||||
is_custom_config ? "Yes" : "No", !auto_config_url.isEmpty() ? auto_config_url_data.constData() : "(null)",
|
||||
service_name, maximum_aggregate_bitrate.has_value() ? "Set" : "Auto",
|
||||
maximum_aggregate_bitrate.value_or(0), maximum_video_tracks.has_value() ? "Set" : "Auto",
|
||||
maximum_video_tracks.value_or(0), rtmp_url.has_value() ? "Yes" : "No",
|
||||
rtmp_url.has_value() ? rtmp_url->c_str() : "",
|
||||
vod_track_info_storage->array ? vod_track_info_storage->array : "No");
|
||||
vod_track_info_storage->array ? vod_track_info_storage->array : "No", canvasNames.c_str());
|
||||
|
||||
const bool custom_config_only = auto_config_url.isEmpty() && MultitrackVideoDeveloperModeEnabled() &&
|
||||
custom_config.has_value() &&
|
||||
@@ -393,7 +413,7 @@ void MultitrackVideoOutput::PrepareStreaming(QWidget *parent, const char *servic
|
||||
|
||||
if (!custom_config_only) {
|
||||
auto go_live_post = constructGoLivePost(stream_key, maximum_aggregate_bitrate, maximum_video_tracks,
|
||||
vod_track_mixer.has_value());
|
||||
vod_track_mixer.has_value(), canvases);
|
||||
|
||||
go_live_config = DownloadGoLiveConfig(parent, auto_config_url, go_live_post, multitrack_video_name);
|
||||
}
|
||||
@@ -436,7 +456,7 @@ void MultitrackVideoOutput::PrepareStreaming(QWidget *parent, const char *servic
|
||||
std::shared_ptr<obs_encoder_group_t> video_encoder_group;
|
||||
auto outputs = SetupOBSOutput(parent, multitrack_video_name, dump_stream_to_file_config, output_config,
|
||||
audio_encoders, video_encoder_group, audio_encoder_id, main_audio_mixer,
|
||||
vod_track_mixer);
|
||||
vod_track_mixer, canvases);
|
||||
auto output = std::move(outputs.output);
|
||||
auto recording_output = std::move(outputs.recording_output);
|
||||
if (!output)
|
||||
@@ -474,6 +494,11 @@ void MultitrackVideoOutput::PrepareStreaming(QWidget *parent, const char *servic
|
||||
recording_audio_encoders.emplace_back(obs_encoder_get_ref(encoder));
|
||||
}
|
||||
|
||||
std::vector<OBSCanvasAutoRelease> recording_canvases(canvases.size());
|
||||
for (const auto &canvas : canvases) {
|
||||
recording_canvases.emplace_back(obs_canvas_get_ref(canvas));
|
||||
}
|
||||
|
||||
{
|
||||
const std::lock_guard current_stream_dump_lock{current_stream_dump_mutex};
|
||||
current_stream_dump.emplace(OBSOutputObjects{
|
||||
@@ -483,6 +508,7 @@ void MultitrackVideoOutput::PrepareStreaming(QWidget *parent, const char *servic
|
||||
nullptr,
|
||||
std::move(start_recording),
|
||||
std::move(stop_recording),
|
||||
std::move(recording_canvases),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -495,6 +521,7 @@ void MultitrackVideoOutput::PrepareStreaming(QWidget *parent, const char *servic
|
||||
std::move(multitrack_video_service),
|
||||
std::move(start_streaming),
|
||||
std::move(stop_streaming),
|
||||
std::move(canvases),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -622,7 +649,7 @@ bool MultitrackVideoOutput::HandleIncompatibleSettings(QWidget *parent, config_t
|
||||
|
||||
static bool create_video_encoders(const GoLiveApi::Config &go_live_config,
|
||||
std::shared_ptr<obs_encoder_group_t> &video_encoder_group, obs_output_t *output,
|
||||
obs_output_t *recording_output)
|
||||
obs_output_t *recording_output, const std::vector<OBSCanvasAutoRelease> &canvases)
|
||||
{
|
||||
DStr video_encoder_name_buffer;
|
||||
if (go_live_config.encoder_configurations.empty()) {
|
||||
@@ -634,9 +661,17 @@ static bool create_video_encoders(const GoLiveApi::Config &go_live_config,
|
||||
if (!encoder_group)
|
||||
return false;
|
||||
|
||||
auto max_canvas_idx = canvases.size() - 1;
|
||||
|
||||
for (size_t i = 0; i < go_live_config.encoder_configurations.size(); i++) {
|
||||
auto encoder =
|
||||
create_video_encoder(video_encoder_name_buffer, i, go_live_config.encoder_configurations[i]);
|
||||
auto &config = go_live_config.encoder_configurations[i];
|
||||
if (config.canvas_index > max_canvas_idx) {
|
||||
blog(LOG_ERROR, "MultitrackVideoOutput: Invalid canvas index: %u", config.canvas_index);
|
||||
throw MultitrackVideoError::warning(QTStr("FailedToStartStream.InvalidEncoderConfig"));
|
||||
}
|
||||
|
||||
auto &canvas = canvases[config.canvas_index];
|
||||
auto encoder = create_video_encoder(video_encoder_name_buffer, i, config, canvas);
|
||||
if (!encoder)
|
||||
return false;
|
||||
|
||||
@@ -797,14 +832,15 @@ static OBSOutputs SetupOBSOutput(QWidget *parent, const QString &multitrack_vide
|
||||
std::vector<OBSEncoderAutoRelease> &audio_encoders,
|
||||
std::shared_ptr<obs_encoder_group_t> &video_encoder_group,
|
||||
const char *audio_encoder_id, size_t main_audio_mixer,
|
||||
std::optional<size_t> vod_track_mixer)
|
||||
std::optional<size_t> vod_track_mixer,
|
||||
const std::vector<OBSCanvasAutoRelease> &canvases)
|
||||
{
|
||||
auto output = create_output();
|
||||
OBSOutputAutoRelease recording_output;
|
||||
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))
|
||||
if (!create_video_encoders(go_live_config, video_encoder_group, output, recording_output, canvases))
|
||||
return {nullptr, nullptr};
|
||||
|
||||
std::vector<speaker_layout> requested_speaker_layouts;
|
||||
|
||||
@@ -27,7 +27,8 @@ public:
|
||||
const char *audio_encoder_id, std::optional<uint32_t> maximum_aggregate_bitrate,
|
||||
std::optional<uint32_t> maximum_video_tracks, std::optional<std::string> custom_config,
|
||||
obs_data_t *dump_stream_to_file_config, size_t main_audio_mixer,
|
||||
std::optional<size_t> vod_track_mixer, std::optional<bool> use_rtmps);
|
||||
std::optional<size_t> vod_track_mixer, std::optional<bool> use_rtmps,
|
||||
std::optional<QString> extra_canvas);
|
||||
signal_handler_t *StreamingSignalHandler();
|
||||
void StartedStreaming();
|
||||
void StopStreaming();
|
||||
@@ -49,6 +50,7 @@ private:
|
||||
std::vector<OBSEncoderAutoRelease> audio_encoders_;
|
||||
OBSServiceAutoRelease multitrack_video_service_;
|
||||
OBSSignal start_signal, stop_signal;
|
||||
std::vector<OBSCanvasAutoRelease> canvases;
|
||||
};
|
||||
|
||||
std::optional<OBSOutputObjects> take_current();
|
||||
|
||||
@@ -173,8 +173,10 @@ bool AutoConfigStreamPage::validatePage()
|
||||
wiz->testMultitrackVideo = ui->useMultitrackVideo->isChecked();
|
||||
|
||||
if (wiz->testMultitrackVideo) {
|
||||
std::vector<OBSCanvasAutoRelease> canvases;
|
||||
canvases.emplace_back(obs_get_main_canvas());
|
||||
auto postData = constructGoLivePost(QString::fromStdString(wiz->key), std::nullopt,
|
||||
std::nullopt, false);
|
||||
std::nullopt, false, canvases);
|
||||
|
||||
OBSDataAutoRelease service_settings = obs_service_get_settings(service);
|
||||
auto multitrack_video_name = QTStr("Basic.Settings.Stream.MultitrackVideoLabel");
|
||||
|
||||
Reference in New Issue
Block a user