Bladeren bron

decklink-output-ui: Decouple DeckLink output state

Didn't realize OBS could output both program and preview views at the
same time with multiple devices.

Also remove render callbacks earlier on stop to avoid use-after-free.

(cherry picked from commit 6aaf0358ca37554b2f2582fcf67e7ff70ac4135b)
jpark37 2 jaren geleden
bovenliggende
commit
16137fb346
1 gewijzigde bestanden met toevoegingen van 47 en 37 verwijderingen
  1. 47 37
      UI/frontend-plugins/decklink-output-ui/decklink-ui-main.cpp

+ 47 - 37
UI/frontend-plugins/decklink-output-ui/decklink-ui-main.cpp

@@ -39,6 +39,7 @@ struct decklink_ui_output {
 };
 };
 
 
 static struct decklink_ui_output context = {0};
 static struct decklink_ui_output context = {0};
+static struct decklink_ui_output context_preview = {0};
 
 
 OBSData load_settings()
 OBSData load_settings()
 {
 {
@@ -61,11 +62,11 @@ static void decklink_ui_render(void *param);
 
 
 void output_stop()
 void output_stop()
 {
 {
+	obs_remove_main_rendered_callback(decklink_ui_render, &context);
+
 	obs_output_stop(context.output);
 	obs_output_stop(context.output);
 	obs_output_release(context.output);
 	obs_output_release(context.output);
 
 
-	obs_remove_main_rendered_callback(decklink_ui_render, &context);
-
 	obs_enter_graphics();
 	obs_enter_graphics();
 	for (gs_stagesurf_t *&surf : context.stagesurfaces) {
 	for (gs_stagesurf_t *&surf : context.stagesurfaces) {
 		gs_stagesurface_destroy(surf);
 		gs_stagesurface_destroy(surf);
@@ -189,27 +190,28 @@ static void decklink_ui_tick(void *param, float /* sec */)
 
 
 void preview_output_stop()
 void preview_output_stop()
 {
 {
-	obs_output_stop(context.output);
-	obs_output_release(context.output);
+	obs_remove_main_rendered_callback(decklink_ui_render, &context_preview);
+	obs_frontend_remove_event_callback(on_preview_scene_changed,
+					   &context_preview);
 
 
-	obs_remove_main_rendered_callback(decklink_ui_render, &context);
-	obs_frontend_remove_event_callback(on_preview_scene_changed, &context);
+	obs_output_stop(context_preview.output);
+	obs_output_release(context_preview.output);
 
 
-	obs_source_release(context.current_source);
+	obs_source_release(context_preview.current_source);
 
 
 	obs_enter_graphics();
 	obs_enter_graphics();
-	for (gs_stagesurf_t *&surf : context.stagesurfaces) {
+	for (gs_stagesurf_t *&surf : context_preview.stagesurfaces) {
 		gs_stagesurface_destroy(surf);
 		gs_stagesurface_destroy(surf);
 		surf = nullptr;
 		surf = nullptr;
 	}
 	}
-	gs_texrender_destroy(context.texrender);
-	context.texrender = nullptr;
-	gs_texrender_destroy(context.texrender_premultiplied);
-	context.texrender_premultiplied = nullptr;
+	gs_texrender_destroy(context_preview.texrender);
+	context_preview.texrender = nullptr;
+	gs_texrender_destroy(context_preview.texrender_premultiplied);
+	context_preview.texrender_premultiplied = nullptr;
 	obs_leave_graphics();
 	obs_leave_graphics();
 
 
-	video_output_close(context.video_queue);
-	obs_remove_tick_callback(decklink_ui_tick, &context);
+	video_output_close(context_preview.video_queue);
+	obs_remove_tick_callback(decklink_ui_tick, &context_preview);
 
 
 	preview_output_running = false;
 	preview_output_running = false;
 
 
@@ -227,58 +229,60 @@ void preview_output_start()
 		const struct video_scale_info *const conversion =
 		const struct video_scale_info *const conversion =
 			obs_output_get_video_conversion(output);
 			obs_output_get_video_conversion(output);
 		if (conversion != nullptr) {
 		if (conversion != nullptr) {
-			context.output = output;
-			obs_add_tick_callback(decklink_ui_tick, &context);
+			context_preview.output = output;
+			obs_add_tick_callback(decklink_ui_tick,
+					      &context_preview);
 
 
-			obs_get_video_info(&context.ovi);
+			obs_get_video_info(&context_preview.ovi);
 
 
 			const uint32_t width = conversion->width;
 			const uint32_t width = conversion->width;
 			const uint32_t height = conversion->height;
 			const uint32_t height = conversion->height;
 
 
 			obs_enter_graphics();
 			obs_enter_graphics();
-			context.texrender_premultiplied =
+			context_preview.texrender_premultiplied =
 				gs_texrender_create(GS_BGRA, GS_ZS_NONE);
 				gs_texrender_create(GS_BGRA, GS_ZS_NONE);
-			context.texrender =
+			context_preview.texrender =
 				gs_texrender_create(GS_BGRA, GS_ZS_NONE);
 				gs_texrender_create(GS_BGRA, GS_ZS_NONE);
-			for (gs_stagesurf_t *&surf : context.stagesurfaces)
+			for (gs_stagesurf_t *&surf :
+			     context_preview.stagesurfaces)
 				surf = gs_stagesurface_create(width, height,
 				surf = gs_stagesurface_create(width, height,
 							      GS_BGRA);
 							      GS_BGRA);
 			obs_leave_graphics();
 			obs_leave_graphics();
 
 
-			for (bool &written : context.surf_written)
+			for (bool &written : context_preview.surf_written)
 				written = false;
 				written = false;
 
 
-			context.stage_index = 0;
+			context_preview.stage_index = 0;
 
 
 			video_output_info vi = {0};
 			video_output_info vi = {0};
 			vi.format = VIDEO_FORMAT_BGRA;
 			vi.format = VIDEO_FORMAT_BGRA;
 			vi.width = width;
 			vi.width = width;
 			vi.height = height;
 			vi.height = height;
-			vi.fps_den = context.ovi.fps_den;
-			vi.fps_num = context.ovi.fps_num;
+			vi.fps_den = context_preview.ovi.fps_den;
+			vi.fps_num = context_preview.ovi.fps_num;
 			vi.cache_size = 16;
 			vi.cache_size = 16;
 			vi.colorspace = VIDEO_CS_DEFAULT;
 			vi.colorspace = VIDEO_CS_DEFAULT;
 			vi.range = VIDEO_RANGE_FULL;
 			vi.range = VIDEO_RANGE_FULL;
 			vi.name = "decklink_preview_output";
 			vi.name = "decklink_preview_output";
 
 
-			video_output_open(&context.video_queue, &vi);
+			video_output_open(&context_preview.video_queue, &vi);
 
 
 			obs_frontend_add_event_callback(
 			obs_frontend_add_event_callback(
-				on_preview_scene_changed, &context);
+				on_preview_scene_changed, &context_preview);
 			if (obs_frontend_preview_program_mode_active()) {
 			if (obs_frontend_preview_program_mode_active()) {
-				context.current_source =
+				context_preview.current_source =
 					obs_frontend_get_current_preview_scene();
 					obs_frontend_get_current_preview_scene();
 			} else {
 			} else {
-				context.current_source =
+				context_preview.current_source =
 					obs_frontend_get_current_scene();
 					obs_frontend_get_current_scene();
 			}
 			}
 			obs_add_main_rendered_callback(decklink_ui_render,
 			obs_add_main_rendered_callback(decklink_ui_render,
-						       &context);
+						       &context_preview);
 
 
-			obs_output_set_media(context.output,
-					     context.video_queue,
+			obs_output_set_media(context_preview.output,
+					     context_preview.video_queue,
 					     obs_get_audio());
 					     obs_get_audio());
-			bool started = obs_output_start(context.output);
+			bool started = obs_output_start(context_preview.output);
 
 
 			preview_output_running = started;
 			preview_output_running = started;
 			if (!shutting_down)
 			if (!shutting_down)
@@ -332,14 +336,20 @@ static void decklink_ui_render(void *param)
 	uint32_t height = 0;
 	uint32_t height = 0;
 	gs_texture_t *tex = nullptr;
 	gs_texture_t *tex = nullptr;
 
 
-	if (main_output_running) {
+	if (ctx == &context) {
+		if (!main_output_running)
+			return;
+
 		tex = obs_get_main_texture();
 		tex = obs_get_main_texture();
 		if (!tex)
 		if (!tex)
 			return;
 			return;
 
 
 		width = gs_texture_get_width(tex);
 		width = gs_texture_get_width(tex);
 		height = gs_texture_get_height(tex);
 		height = gs_texture_get_height(tex);
-	} else if (preview_output_running) {
+	} else if (ctx == &context_preview) {
+		if (!preview_output_running)
+			return;
+
 		if (!ctx->current_source)
 		if (!ctx->current_source)
 			return;
 			return;
 
 
@@ -372,7 +382,7 @@ static void decklink_ui_render(void *param)
 	}
 	}
 
 
 	const struct video_scale_info *const conversion =
 	const struct video_scale_info *const conversion =
-		obs_output_get_video_conversion(context.output);
+		obs_output_get_video_conversion(ctx->output);
 	const uint32_t scaled_width = conversion->width;
 	const uint32_t scaled_width = conversion->width;
 	const uint32_t scaled_height = conversion->height;
 	const uint32_t scaled_height = conversion->height;
 
 
@@ -380,8 +390,8 @@ static void decklink_ui_render(void *param)
 		return;
 		return;
 
 
 	const bool previous = gs_framebuffer_srgb_enabled();
 	const bool previous = gs_framebuffer_srgb_enabled();
-	const bool source_hdr = (context.ovi.colorspace == VIDEO_CS_2100_PQ) ||
-				(context.ovi.colorspace == VIDEO_CS_2100_HLG);
+	const bool source_hdr = (ctx->ovi.colorspace == VIDEO_CS_2100_PQ) ||
+				(ctx->ovi.colorspace == VIDEO_CS_2100_HLG);
 	const bool target_hdr = source_hdr &&
 	const bool target_hdr = source_hdr &&
 				(conversion->colorspace == VIDEO_CS_2100_PQ);
 				(conversion->colorspace == VIDEO_CS_2100_PQ);
 	gs_enable_framebuffer_srgb(!target_hdr);
 	gs_enable_framebuffer_srgb(!target_hdr);