obs-webrtc: Add Simulcast Support · obsproject/obs-studio@cd4d624

2 min read Original article ↗
1+

/******************************************************************************

2+

Copyright (C) 2025 by Sean DuBois <sean@pion.ly>

3+4+

This program is free software: you can redistribute it and/or modify

5+

it under the terms of the GNU General Public License as published by

6+

the Free Software Foundation, either version 2 of the License, or

7+

(at your option) any later version.

8+9+

This program is distributed in the hope that it will be useful,

10+

but WITHOUT ANY WARRANTY; without even the implied warranty of

11+

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

12+

GNU General Public License for more details.

13+14+

You should have received a copy of the GNU General Public License

15+

along with this program. If not, see <http://www.gnu.org/licenses/>.

16+

******************************************************************************/

17+

#pragma once

18+19+

struct WHIPSimulcastEncoders {

20+

public:

21+

void Create(const char *encoderId, int rescaleFilter, int whipSimulcastTotalLayers, uint32_t outputWidth,

22+

uint32_t outputHeight)

23+

{

24+

if (rescaleFilter == OBS_SCALE_DISABLE) {

25+

rescaleFilter = OBS_SCALE_BICUBIC;

26+

}

27+28+

if (whipSimulcastTotalLayers <= 1) {

29+

return;

30+

}

31+32+

auto widthStep = outputWidth / whipSimulcastTotalLayers;

33+

auto heightStep = outputHeight / whipSimulcastTotalLayers;

34+

std::string encoder_name = "whip_simulcast_0";

35+36+

for (auto i = whipSimulcastTotalLayers - 1; i > 0; i--) {

37+

uint32_t width = widthStep * i;

38+

width -= width % 2;

39+40+

uint32_t height = heightStep * i;

41+

height -= height % 2;

42+43+

encoder_name[encoder_name.size() - 1] = std::to_string(i).at(0);

44+

auto whip_simulcast_encoder =

45+

obs_video_encoder_create(encoderId, encoder_name.c_str(), nullptr, nullptr);

46+47+

if (whip_simulcast_encoder) {

48+

obs_encoder_set_video(whip_simulcast_encoder, obs_get_video());

49+

obs_encoder_set_scaled_size(whip_simulcast_encoder, width, height);

50+

obs_encoder_set_gpu_scale_type(whip_simulcast_encoder, (obs_scale_type)rescaleFilter);

51+

whipSimulcastEncoders.push_back(whip_simulcast_encoder);

52+

obs_encoder_release(whip_simulcast_encoder);

53+

} else {

54+

blog(LOG_WARNING,

55+

"Failed to create video streaming WHIP Simulcast encoders (BasicOutputHandler)");

56+

}

57+

}

58+

}

59+60+

void Update(obs_data_t *videoSettings, int videoBitrate)

61+

{

62+

auto bitrateStep = videoBitrate / static_cast<int>(whipSimulcastEncoders.size() + 1);

63+

for (auto &whipSimulcastEncoder : whipSimulcastEncoders) {

64+

videoBitrate -= bitrateStep;

65+

obs_data_set_int(videoSettings, "bitrate", videoBitrate);

66+

obs_encoder_update(whipSimulcastEncoder, videoSettings);

67+

}

68+

}

69+70+

void SetVideoFormat(enum video_format format)

71+

{

72+

for (auto enc : whipSimulcastEncoders)

73+

obs_encoder_set_preferred_video_format(enc, format);

74+

}

75+76+

void SetStreamOutput(obs_output_t *streamOutput)

77+

{

78+

for (size_t i = 0; i < whipSimulcastEncoders.size(); i++)

79+

obs_output_set_video_encoder2(streamOutput, whipSimulcastEncoders[i], i + 1);

80+

}

81+82+

private:

83+

std::vector<OBSEncoder> whipSimulcastEncoders;

84+

};