2323#include < util/dstr.h>
2424#include " utility.hpp"
2525
26+ static bool codecListContains (const char **codecs, const char *codec);
27+ static const char *getStreamOutputType (const obs_service_t *service);
2628static bool isNvencAvailableForSimpleMode ();
2729static bool containerSupportsCodec (const std::string &container, const std::string &codec);
2830static void convert_nvenc_h264_presets (obs_data_t *data);
@@ -104,18 +106,81 @@ bool osn::EncoderUtils::isCodecAvailableForService(const char *encoder, obs_serv
104106 auto supportedCodecs = obs_service_get_supported_video_codecs (service);
105107 auto encoderCodec = obs_get_encoder_codec (encoder);
106108
107- if (!supportedCodecs || ! encoderCodec)
109+ if (!encoderCodec)
108110 return false ;
109111
110- while (*supportedCodecs) {
111- if (strcmp (*supportedCodecs, encoderCodec) == 0 )
112+ if (supportedCodecs)
113+ return codecListContains (supportedCodecs, encoderCodec);
114+
115+ // Custom services do not expose codec lists, so mirror OBS and fall back to the output type.
116+ auto outputType = getStreamOutputType (service);
117+ if (!outputType)
118+ return false ;
119+
120+ auto outputSupportedCodecs = obs_get_output_supported_video_codecs (outputType);
121+ if (!outputSupportedCodecs)
122+ return false ;
123+
124+ auto splitOutputSupportedCodecs = strlist_split (outputSupportedCodecs, ' ;' , false );
125+ bool supported = codecListContains ((const char **)splitOutputSupportedCodecs, encoderCodec);
126+ strlist_free (splitOutputSupportedCodecs);
127+
128+ return supported;
129+ }
130+
131+ static bool codecListContains (const char **codecs, const char *codec)
132+ {
133+ if (!codecs || !codec)
134+ return false ;
135+
136+ while (*codecs) {
137+ if (strcmp (*codecs, codec) == 0 )
112138 return true ;
113- supportedCodecs ++;
139+ codecs ++;
114140 }
115141
116142 return false ;
117143}
118144
145+ // Resolves the OBS output type used by a streaming service.
146+ // Returns a non-owned output type ID, such as "rtmp_output", or nullptr if no compatible output is registered.
147+ static const char *getStreamOutputType (const obs_service_t *service)
148+ {
149+ const char *protocol = obs_service_get_protocol (service);
150+
151+ if (!protocol)
152+ return nullptr ;
153+
154+ if (!obs_is_output_protocol_registered (protocol))
155+ return nullptr ;
156+
157+ const char *output = obs_service_get_preferred_output_type (service);
158+ if (output && (obs_get_output_flags (output) & OBS_OUTPUT_SERVICE) != 0 )
159+ return output;
160+
161+ auto canUseOutput = [](const char *prot, const char *output, const char *prot_test1, const char *prot_test2 = nullptr ) {
162+ return (strcmp (prot, prot_test1) == 0 || (prot_test2 && strcmp (prot, prot_test2) == 0 )) &&
163+ (obs_get_output_flags (output) & OBS_OUTPUT_SERVICE) != 0 ;
164+ };
165+
166+ if (canUseOutput (protocol, " rtmp_output" , " RTMP" , " RTMPS" )) {
167+ return " rtmp_output" ;
168+ } else if (canUseOutput (protocol, " ffmpeg_hls_muxer" , " HLS" )) {
169+ return " ffmpeg_hls_muxer" ;
170+ } else if (canUseOutput (protocol, " ffmpeg_mpegts_muxer" , " SRT" , " RIST" )) {
171+ return " ffmpeg_mpegts_muxer" ;
172+ }
173+
174+ auto returnFirstOutputId = [](void *data, const char *id) {
175+ const char **output = (const char **)data;
176+
177+ *output = id;
178+ return false ;
179+ };
180+ obs_enum_output_types_with_protocol (protocol, &output, returnFirstOutputId);
181+ return output;
182+ }
183+
119184bool osn::EncoderUtils::isEncoderCompatible (std::string encoderName, obs_service_t *service, bool simpleMode, bool recording, const std::string &container,
120185 int checkIndex)
121186{
@@ -517,4 +582,4 @@ static void convert_nvenc_hevc_presets(obs_data_t *data)
517582 obs_data_set_string (data, " tune" , " ll" );
518583 obs_data_set_string (data, " multipass" , " disabled" );
519584 }
520- }
585+ }
0 commit comments