@@ -1181,6 +1181,8 @@ namespace video {
11811181 int active_av1_mode;
11821182 bool last_encoder_probe_supported_ref_frames_invalidation = false ;
11831183 std::array<bool , 3 > last_encoder_probe_supported_yuv444_for_codec = {};
1184+ constexpr auto no_display_available_msg = " Unable to start capture because no display is available" sv;
1185+ constexpr auto no_encoder_selected_msg = " No encoder selected; aborting capture instead of using invalid encoder state" sv;
11841186
11851187 void reset_display (std::shared_ptr<platf::display_t > &disp, const platf::mem_type_e &type, const std::string &display_name, const config_t &config) {
11861188 // We try this twice, in case we still get an error on reinitialization
@@ -1214,16 +1216,18 @@ namespace video {
12141216 }
12151217
12161218 // Refresh the display names
1217- auto old_display_names = std::move ( display_names);
1219+ auto had_display_names = ! display_names. empty ( );
12181220 display_names = platf::display_names (dev_type);
12191221
1220- // If we now have no displays, let's put the old display array back and fail
1221- if (display_names.empty () && !old_display_names.empty ()) {
1222- BOOST_LOG (error) << " No displays were found after reenumeration!" sv;
1223- display_names = std::move (old_display_names);
1224- return ;
1225- } else if (display_names.empty ()) {
1226- display_names.emplace_back (output_name);
1222+ // If we now have no displays, fail instead of reusing stale display names.
1223+ if (display_names.empty ()) {
1224+ if (!had_display_names && !output_name.empty ()) {
1225+ display_names.emplace_back (output_name);
1226+ } else {
1227+ BOOST_LOG (error) << (had_display_names ? " No displays were found after reenumeration!" sv : " No displays were found during enumeration!" sv);
1228+ current_display_index = -1 ;
1229+ return ;
1230+ }
12271231 }
12281232
12291233 // We now have a new display name list, so reset the index back to 0
@@ -1284,6 +1288,10 @@ namespace video {
12841288 std::vector<std::string> display_names;
12851289 int display_p = -1 ;
12861290 refresh_displays (encoder.platform_formats ->dev_type , display_names, display_p);
1291+ if (display_p < 0 || display_names.empty ()) {
1292+ BOOST_LOG (error) << no_display_available_msg;
1293+ return ;
1294+ }
12871295 auto disp = platf::display (encoder.platform_formats ->dev_type , display_names[display_p], capture_ctxs.front ().config );
12881296 if (!disp) {
12891297 return ;
@@ -1897,27 +1905,34 @@ namespace video {
18971905 // Allow the encoding device a final opportunity to set/unset or override any options
18981906 encode_device->init_codec_options (ctx.get (), &options);
18991907
1900- if (auto status = avcodec_open2 (ctx.get (), codec, &options)) {
1901- char err_str[AV_ERROR_MAX_STRING_SIZE ] {0 };
1908+ auto status = avcodec_open2 (ctx.get (), codec, &options);
1909+ if (!status) {
1910+ // Successfully opened the codec
1911+ break ;
1912+ }
19021913
1903- if (!video_format.fallback_options .empty () && retries == 0 ) {
1904- BOOST_LOG (info)
1905- << " Retrying with fallback configuration options for [" sv << video_format.name << " ] after error: " sv
1906- << av_make_error_string (err_str, AV_ERROR_MAX_STRING_SIZE , status);
1914+ char err_str[AV_ERROR_MAX_STRING_SIZE ] {0 };
1915+ if (!video_format.fallback_options .empty () && retries == 0 ) {
1916+ BOOST_LOG (info)
1917+ << " Retrying with fallback configuration options for [" sv << video_format.name << " ] after error: " sv
1918+ << av_make_error_string (err_str, AV_ERROR_MAX_STRING_SIZE , status);
19071919
1908- continue ;
1909- } else {
1910- BOOST_LOG (error)
1911- << " Could not open codec [" sv
1912- << video_format.name << " ]: " sv
1913- << av_make_error_string (err_str, AV_ERROR_MAX_STRING_SIZE , status);
1920+ continue ;
1921+ }
19141922
1915- return nullptr ;
1916- }
1923+ BOOST_LOG (error)
1924+ << " Could not open codec [" sv
1925+ << video_format.name << " ]: " sv
1926+ << av_make_error_string (err_str, AV_ERROR_MAX_STRING_SIZE , status);
1927+
1928+ if (encoder.name == " vulkan" sv) {
1929+ BOOST_LOG (error)
1930+ << " Vulkan encoder setup failed for [" sv << video_format.name
1931+ << " ]; this GPU or driver does not expose the required Vulkan video encode capability. "
1932+ << " Sunshine will discard this encoder and continue probing fallback encoders." sv;
19171933 }
19181934
1919- // Successfully opened the codec
1920- break ;
1935+ return nullptr ;
19211936 }
19221937
19231938 avcodec_frame_t frame {av_frame_alloc ()};
@@ -2286,6 +2301,10 @@ namespace video {
22862301 while (encode_session_ctx_queue.running ()) {
22872302 // Refresh display names since a display removal might have caused the reinitialization
22882303 refresh_displays (encoder.platform_formats ->dev_type , display_names, display_p);
2304+ if (display_p < 0 || display_names.empty ()) {
2305+ BOOST_LOG (error) << no_display_available_msg;
2306+ return encode_e::error;
2307+ }
22892308
22902309 // Process any pending display switch with the new list of displays
22912310 if (switch_display_event->peek ()) {
@@ -2491,6 +2510,11 @@ namespace video {
24912510 display = ref->display_wp ->lock ();
24922511 }
24932512
2513+ if (!chosen_encoder) {
2514+ BOOST_LOG (error) << no_encoder_selected_msg;
2515+ return ;
2516+ }
2517+
24942518 auto &encoder = *chosen_encoder;
24952519
24962520 auto encode_device = make_encode_device (*display, encoder, config);
@@ -2533,6 +2557,11 @@ namespace video {
25332557 ) {
25342558 auto idr_events = mail->event <bool >(mail::idr);
25352559
2560+ if (!chosen_encoder) {
2561+ BOOST_LOG (error) << no_encoder_selected_msg;
2562+ return ;
2563+ }
2564+
25362565 idr_events->raise (true );
25372566 if (chosen_encoder->flags & PARALLEL_ENCODING ) {
25382567 capture_async (std::move (mail), config, channel_data);
@@ -3013,6 +3042,7 @@ namespace video {
30133042
30143043 if (encode_device && encode_device->data ) {
30153044 if (((vulkan_init_avcodec_hardware_input_buffer_fn) encode_device->data )(encode_device, &hw_device_buf)) {
3045+ BOOST_LOG (error) << " Failed to create a Vulkan device from the capture backend; aborting Vulkan encoder setup" sv;
30163046 return -1 ;
30173047 }
30183048 return hw_device_buf;
0 commit comments