Quellcode durchsuchen

Merge pull request #7814 from jpark37/decklink-preview-rescale

decklink: Move preview output rescaling to GPU
Jim vor 2 Jahren
Ursprung
Commit
0a9ed4569b

+ 51 - 9
UI/frontend-plugins/decklink-output-ui/decklink-ui-main.cpp

@@ -29,6 +29,7 @@ struct preview_output {
 	obs_output_t *output;
 
 	video_t *video_queue;
+	gs_texrender_t *texrender_premultiplied;
 	gs_texrender_t *texrender;
 	gs_stagesurf_t *stagesurfaces[STAGE_BUFFER_COUNT];
 	bool surf_written[STAGE_BUFFER_COUNT];
@@ -120,6 +121,8 @@ static void preview_tick(void *param, float sec)
 
 	auto ctx = (struct preview_output *)param;
 
+	if (ctx->texrender_premultiplied)
+		gs_texrender_reset(ctx->texrender_premultiplied);
 	if (ctx->texrender)
 		gs_texrender_reset(ctx->texrender);
 }
@@ -135,9 +138,14 @@ void preview_output_stop()
 	obs_source_release(context.current_source);
 
 	obs_enter_graphics();
-	for (gs_stagesurf_t *surf : context.stagesurfaces)
+	for (gs_stagesurf_t *&surf : context.stagesurfaces) {
 		gs_stagesurface_destroy(surf);
+		surf = nullptr;
+	}
 	gs_texrender_destroy(context.texrender);
+	context.texrender = nullptr;
+	gs_texrender_destroy(context.texrender_premultiplied);
+	context.texrender_premultiplied = nullptr;
 	obs_leave_graphics();
 
 	video_output_close(context.video_queue);
@@ -161,10 +169,14 @@ void preview_output_start()
 
 		obs_get_video_info(&context.ovi);
 
-		uint32_t width = context.ovi.base_width;
-		uint32_t height = context.ovi.base_height;
+		const struct video_scale_info *const conversion =
+			obs_output_get_video_conversion(context.output);
+		const uint32_t width = conversion->width;
+		const uint32_t height = conversion->height;
 
 		obs_enter_graphics();
+		context.texrender_premultiplied =
+			gs_texrender_create(GS_BGRA, GS_ZS_NONE);
 		context.texrender = gs_texrender_create(GS_BGRA, GS_ZS_NONE);
 		for (gs_stagesurf_t *&surf : context.stagesurfaces)
 			surf = gs_stagesurface_create(width, height, GS_BGRA);
@@ -257,10 +269,17 @@ void render_preview_source(void *param, uint32_t cx, uint32_t cy)
 	if (!ctx->current_source)
 		return;
 
-	uint32_t width = obs_source_get_base_width(ctx->current_source);
-	uint32_t height = obs_source_get_base_height(ctx->current_source);
+	const uint32_t width = obs_source_get_base_width(ctx->current_source);
+	const uint32_t height = obs_source_get_base_height(ctx->current_source);
+
+	const struct video_scale_info *const conversion =
+		obs_output_get_video_conversion(context.output);
+	const uint32_t scaled_width = conversion->width;
+	const uint32_t scaled_height = conversion->height;
 
-	if (gs_texrender_begin(ctx->texrender, width, height)) {
+	gs_texrender_t *const texrender_premultiplied =
+		ctx->texrender_premultiplied;
+	if (gs_texrender_begin(texrender_premultiplied, width, height)) {
 		struct vec4 background;
 		vec4_zero(&background);
 
@@ -274,7 +293,30 @@ void render_preview_source(void *param, uint32_t cx, uint32_t cy)
 		obs_source_video_render(ctx->current_source);
 
 		gs_blend_state_pop();
-		gs_texrender_end(ctx->texrender);
+		gs_texrender_end(texrender_premultiplied);
+
+		if (gs_texrender_begin(ctx->texrender, scaled_width,
+				       scaled_height)) {
+			const bool previous = gs_framebuffer_srgb_enabled();
+			gs_enable_framebuffer_srgb(true);
+			gs_enable_blending(false);
+
+			gs_texture_t *const tex = gs_texrender_get_texture(
+				texrender_premultiplied);
+			gs_effect_t *const effect =
+				obs_get_base_effect(OBS_EFFECT_DEFAULT);
+			gs_effect_set_texture_srgb(
+				gs_effect_get_param_by_name(effect, "image"),
+				tex);
+			while (gs_effect_loop(effect, "DrawAlphaDivide")) {
+				gs_draw_sprite(tex, 0, 0, 0);
+			}
+
+			gs_enable_blending(true);
+			gs_enable_framebuffer_srgb(previous);
+
+			gs_texrender_end(ctx->texrender);
+		}
 
 		const size_t write_stage_index = ctx->stage_index;
 		gs_stage_texture(ctx->stagesurfaces[write_stage_index],
@@ -295,8 +337,8 @@ void render_preview_source(void *param, uint32_t cx, uint32_t cy)
 							&ctx->video_linesize)) {
 					uint32_t linesize =
 						output_frame.linesize[0];
-					for (uint32_t i = 0;
-					     i < ctx->ovi.base_height; i++) {
+					for (uint32_t i = 0; i < scaled_height;
+					     i++) {
 						uint32_t dst_offset =
 							linesize * i;
 						uint32_t src_offset =

+ 3 - 2
docs/sphinx/reference-outputs.rst

@@ -741,9 +741,10 @@ Functions used by outputs
 ---------------------
 
 .. function:: void obs_output_set_video_conversion(obs_output_t *output, const struct video_scale_info *conversion)
+              const struct video_scale_info *obs_output_get_video_conversion(obs_output_t *output)
 
-   Optionally sets the video conversion information.  Only used by raw
-   outputs.
+   Optionally sets/gets the video conversion information.  Only used by
+   raw outputs.
 
    Relevant data types used with this function:
 

+ 3 - 3
libobs/obs-output.c

@@ -1099,8 +1099,8 @@ static inline bool has_scaling(const struct obs_output *output)
 		video_height != output->scaled_height);
 }
 
-static inline struct video_scale_info *
-get_video_conversion(struct obs_output *output)
+const struct video_scale_info *
+obs_output_get_video_conversion(struct obs_output *output)
 {
 	if (output->video_conversion_set) {
 		if (!output->video_conversion.width)
@@ -1991,7 +1991,7 @@ static void hook_data_capture(struct obs_output *output, bool encoded,
 	} else {
 		if (has_video)
 			start_raw_video(output->video,
-					get_video_conversion(output),
+					obs_output_get_video_conversion(output),
 					default_raw_video_callback, output);
 		if (has_audio)
 			start_raw_audio(output);

+ 4 - 0
libobs/obs.h

@@ -2230,6 +2230,10 @@ EXPORT const char *obs_get_output_supported_audio_codecs(const char *id);
 
 EXPORT void *obs_output_get_type_data(obs_output_t *output);
 
+/** Gets the video conversion info.  Used only for raw output */
+EXPORT const struct video_scale_info *
+obs_output_get_video_conversion(obs_output_t *output);
+
 /** Optionally sets the video conversion info.  Used only for raw output */
 EXPORT void
 obs_output_set_video_conversion(obs_output_t *output,

+ 16 - 9
plugins/decklink/decklink-output.cpp

@@ -25,6 +25,22 @@ static void *decklink_output_create(obs_data_t *settings, obs_output_t *output)
 	decklinkOutput->modeID = obs_data_get_int(settings, MODE_ID);
 	decklinkOutput->keyerMode = (int)obs_data_get_int(settings, KEYER);
 
+	ComPtr<DeckLinkDevice> device;
+	device.Set(deviceEnum->FindByHash(decklinkOutput->deviceHash));
+	if (device) {
+		DeckLinkDeviceMode *mode =
+			device->FindOutputMode(decklinkOutput->modeID);
+
+		struct video_scale_info to = {};
+		to.format = VIDEO_FORMAT_BGRA;
+		to.width = mode->GetWidth();
+		to.height = mode->GetHeight();
+		to.range = VIDEO_RANGE_FULL;
+		to.colorspace = VIDEO_CS_709;
+
+		obs_output_set_video_conversion(output, &to);
+	}
+
 	return decklinkOutput;
 }
 
@@ -80,15 +96,6 @@ static bool decklink_output_start(void *data)
 
 	decklink->SetSize(mode->GetWidth(), mode->GetHeight());
 
-	struct video_scale_info to = {};
-	to.format = VIDEO_FORMAT_BGRA;
-	to.width = mode->GetWidth();
-	to.height = mode->GetHeight();
-	to.range = VIDEO_RANGE_FULL;
-	to.colorspace = VIDEO_CS_709;
-
-	obs_output_set_video_conversion(decklink->GetOutput(), &to);
-
 	device->SetKeyerMode(decklink->keyerMode);
 
 	if (!decklink->Activate(device, decklink->modeID))