@@ -541,6 +541,8 @@ void SimpleOutput::LoadStreamingPreset_Lossy(const char *encoderId)
541541 if (!videoStreaming)
542542 throw " Failed to create video streaming encoder (simple output)" ;
543543 obs_encoder_release (videoStreaming);
544+
545+ CreateSimulcastEncoders (encoderId);
544546}
545547
546548/* mistakes have been made to lead us to this. */
@@ -800,11 +802,14 @@ void SimpleOutput::Update()
800802 break ;
801803 default :
802804 obs_encoder_set_preferred_video_format (videoStreaming, VIDEO_FORMAT_NV12);
805+ for (auto enc : simulcastEncoders)
806+ obs_encoder_set_preferred_video_format (enc, VIDEO_FORMAT_NV12);
803807 }
804808
805809 obs_encoder_update (videoStreaming, videoSettings);
806810 obs_encoder_update (audioStreaming, audioSettings);
807811 obs_encoder_update (audioArchive, audioSettings);
812+ SimulcastEncodersUpdate (videoSettings, videoBitrate);
808813}
809814
810815void SimpleOutput::UpdateRecordingAudioSettings ()
@@ -1094,6 +1099,8 @@ std::shared_future<void> SimpleOutput::SetupStreaming(obs_service_t *service, Se
10941099 }
10951100
10961101 obs_output_set_video_encoder (streamOutput, videoStreaming);
1102+ for (size_t i = 0 ; i < simulcastEncoders.size (); i++)
1103+ obs_output_set_video_encoder2 (streamOutput, simulcastEncoders[i], i + 1 );
10971104 obs_output_set_audio_encoder (streamOutput, audioStreaming, 0 );
10981105 obs_output_set_service (streamOutput, service);
10991106 return true ;
@@ -1568,6 +1575,7 @@ AdvancedOutput::AdvancedOutput(OBSBasic *main_) : BasicOutputHandler(main_)
15681575 throw " Failed to create streaming video encoder "
15691576 " (advanced output)" ;
15701577 obs_encoder_release (videoStreaming);
1578+ CreateSimulcastEncoders (streamEncoder);
15711579
15721580 const char *rate_control =
15731581 obs_data_get_string (useStreamEncoder ? streamEncSettings : recordEncSettings, " rate_control" );
@@ -1668,6 +1676,7 @@ void AdvancedOutput::UpdateStreamSettings()
16681676 }
16691677
16701678 obs_encoder_update (videoStreaming, settings);
1679+ SimulcastEncodersUpdate (settings, obs_data_get_int (settings, " bitrate" ));
16711680}
16721681
16731682inline void AdvancedOutput::UpdateRecordingSettings ()
@@ -2082,6 +2091,8 @@ std::shared_future<void> AdvancedOutput::SetupStreaming(obs_service_t *service,
20822091 }
20832092
20842093 obs_output_set_video_encoder (streamOutput, videoStreaming);
2094+ for (size_t i = 0 ; i < simulcastEncoders.size (); i++)
2095+ obs_output_set_video_encoder2 (streamOutput, simulcastEncoders[i], i + 1 );
20852096 obs_output_set_audio_encoder (streamOutput, streamAudioEnc, 0 );
20862097
20872098 if (!is_multitrack_output) {
@@ -2539,3 +2550,51 @@ BasicOutputHandler *CreateAdvancedOutputHandler(OBSBasic *main)
25392550{
25402551 return new AdvancedOutput (main);
25412552}
2553+
2554+ void BasicOutputHandler::CreateSimulcastEncoders (const char *encoderId)
2555+ {
2556+ int rescaleFilter = config_get_int (main->Config (), " AdvOut" , " RescaleFilter" );
2557+ if (rescaleFilter == OBS_SCALE_DISABLE) {
2558+ rescaleFilter = OBS_SCALE_BICUBIC;
2559+ }
2560+
2561+ std::string encoder_name = " simulcast_0" ;
2562+ auto simulcastTotalLayers = config_get_int (main->Config (), " Stream1" , " SimulcastTotalLayers" );
2563+ if (simulcastTotalLayers <= 1 ) {
2564+ return ;
2565+ }
2566+
2567+ auto widthStep = video_output_get_width (obs_get_video ()) / simulcastTotalLayers;
2568+ auto heightStep = video_output_get_height (obs_get_video ()) / simulcastTotalLayers;
2569+
2570+ for (auto i = simulcastTotalLayers - 1 ; i > 0 ; i--) {
2571+ uint32_t width = widthStep * i;
2572+ width -= width % 2 ;
2573+
2574+ uint32_t height = heightStep * i;
2575+ height -= height % 2 ;
2576+
2577+ encoder_name[encoder_name.size () - 1 ] = to_string (i).at (0 );
2578+ auto simulcast_encoder = obs_video_encoder_create (encoderId, encoder_name.c_str (), nullptr , nullptr );
2579+
2580+ if (simulcast_encoder) {
2581+ obs_encoder_set_video (simulcast_encoder, obs_get_video ());
2582+ obs_encoder_set_scaled_size (simulcast_encoder, width, height);
2583+ obs_encoder_set_gpu_scale_type (simulcast_encoder, (obs_scale_type)rescaleFilter);
2584+ simulcastEncoders.push_back (simulcast_encoder);
2585+ obs_encoder_release (simulcast_encoder);
2586+ } else {
2587+ blog (LOG_WARNING, " Failed to create video streaming simulcast encoders (BasicOutputHandler)" );
2588+ }
2589+ }
2590+ }
2591+
2592+ void BasicOutputHandler::SimulcastEncodersUpdate (obs_data_t *videoSettings, int videoBitrate)
2593+ {
2594+ auto bitrateStep = videoBitrate / static_cast <int >(simulcastEncoders.size () + 1 );
2595+ for (auto &simulcastEncoder : simulcastEncoders) {
2596+ videoBitrate -= bitrateStep;
2597+ obs_data_set_int (videoSettings, " bitrate" , videoBitrate);
2598+ obs_encoder_update (simulcastEncoder, videoSettings);
2599+ }
2600+ }
0 commit comments