diff --git a/plugins/obs-filters/scale-filter.c b/plugins/obs-filters/scale-filter.c index eca35e486..6e7256b1d 100644 --- a/plugins/obs-filters/scale-filter.c +++ b/plugins/obs-filters/scale-filter.c @@ -38,6 +38,7 @@ struct scale_filter_data { gs_eparam_t *dimension_param; gs_eparam_t *dimension_i_param; gs_eparam_t *undistort_factor_param; + gs_eparam_t *multiplier_param; struct vec2 dimension; struct vec2 dimension_i; double undistort_factor; @@ -264,23 +265,166 @@ static void scale_filter_tick(void *data, float seconds) filter->undistort_factor_param = NULL; } + filter->multiplier_param = + gs_effect_get_param_by_name(filter->effect, "multiplier"); + UNUSED_PARAMETER(seconds); } +static const char * +get_tech_name_and_multiplier(const struct scale_filter_data *filter, + enum gs_color_space current_space, + enum gs_color_space source_space, + float *multiplier) +{ + *multiplier = 1.f; + switch (source_space) { + case GS_CS_SRGB: + case GS_CS_SRGB_16F: + switch (current_space) { + case GS_CS_709_SCRGB: + *multiplier = obs_get_video_sdr_white_level() / 80.f; + } + break; + case GS_CS_709_EXTENDED: + switch (current_space) { + case GS_CS_709_SCRGB: + *multiplier = obs_get_video_sdr_white_level() / 80.f; + } + break; + case GS_CS_709_SCRGB: + switch (current_space) { + case GS_CS_SRGB: + case GS_CS_SRGB_16F: + case GS_CS_709_EXTENDED: + *multiplier = 80.f / obs_get_video_sdr_white_level(); + } + } + + const char *tech_name = "Draw"; + if (filter->undistort) { + tech_name = "DrawUndistort"; + switch (source_space) { + case GS_CS_SRGB: + case GS_CS_SRGB_16F: + switch (current_space) { + case GS_CS_709_SCRGB: + tech_name = "DrawUndistortMultiply"; + } + break; + case GS_CS_709_EXTENDED: + switch (current_space) { + case GS_CS_SRGB: + case GS_CS_SRGB_16F: + tech_name = "DrawUndistortTonemap"; + break; + case GS_CS_709_SCRGB: + tech_name = "DrawUndistortMultiply"; + } + break; + case GS_CS_709_SCRGB: + switch (current_space) { + case GS_CS_SRGB: + case GS_CS_SRGB_16F: + tech_name = "DrawUndistortMultiplyTonemap"; + break; + case GS_CS_709_EXTENDED: + tech_name = "DrawUndistortMultiply"; + } + } + } else if (filter->upscale) { + tech_name = "DrawUpscale"; + switch (source_space) { + case GS_CS_SRGB: + case GS_CS_SRGB_16F: + switch (current_space) { + case GS_CS_709_SCRGB: + tech_name = "DrawUpscaleMultiply"; + } + break; + case GS_CS_709_EXTENDED: + switch (current_space) { + case GS_CS_SRGB: + case GS_CS_SRGB_16F: + tech_name = "DrawUpscaleTonemap"; + break; + case GS_CS_709_SCRGB: + tech_name = "DrawUpscaleMultiply"; + } + break; + case GS_CS_709_SCRGB: + switch (current_space) { + case GS_CS_SRGB: + case GS_CS_SRGB_16F: + tech_name = "DrawUpscaleMultiplyTonemap"; + break; + case GS_CS_709_EXTENDED: + tech_name = "DrawUpscaleMultiply"; + } + } + } else { + switch (source_space) { + case GS_CS_SRGB: + case GS_CS_SRGB_16F: + switch (current_space) { + case GS_CS_709_SCRGB: + tech_name = "DrawMultiply"; + } + break; + case GS_CS_709_EXTENDED: + switch (current_space) { + case GS_CS_SRGB: + case GS_CS_SRGB_16F: + tech_name = "DrawTonemap"; + break; + case GS_CS_709_SCRGB: + tech_name = "DrawMultiply"; + } + break; + case GS_CS_709_SCRGB: + switch (current_space) { + case GS_CS_SRGB: + case GS_CS_SRGB_16F: + tech_name = "DrawMultiplyTonemap"; + break; + case GS_CS_709_EXTENDED: + tech_name = "DrawMultiply"; + } + } + } + + return tech_name; +} + static void scale_filter_render(void *data, gs_effect_t *effect) { struct scale_filter_data *filter = data; - const char *technique = - filter->undistort ? "DrawUndistort" - : (filter->upscale ? "DrawUpscale" : "Draw"); + + const enum gs_color_space current_space = gs_get_color_space(); + + const enum gs_color_space preferred_spaces[] = { + GS_CS_SRGB, + GS_CS_SRGB_16F, + GS_CS_709_EXTENDED, + }; + + const enum gs_color_space source_space = obs_source_get_color_space( + obs_filter_get_parent(filter->context), + OBS_COUNTOF(preferred_spaces), preferred_spaces); + float multiplier; + const char *technique = get_tech_name_and_multiplier( + filter, current_space, source_space, &multiplier); if (!filter->valid || !filter->target_valid) { obs_source_skip_video_filter(filter->context); return; } - if (!obs_source_process_filter_begin(filter->context, GS_RGBA, - OBS_NO_DIRECT_RENDERING)) + const enum gs_color_format format = + gs_get_format_from_space(source_space); + if (!obs_source_process_filter_begin_with_color_space( + filter->context, format, source_space, + OBS_NO_DIRECT_RENDERING)) return; if (filter->dimension_param) @@ -294,6 +438,9 @@ static void scale_filter_render(void *data, gs_effect_t *effect) gs_effect_set_float(filter->undistort_factor_param, (float)filter->undistort_factor); + if (filter->multiplier_param) + gs_effect_set_float(filter->multiplier_param, multiplier); + if (filter->sampling == OBS_SCALE_POINT) gs_effect_set_next_sampler(filter->image_param, filter->point_sampler); @@ -425,6 +572,31 @@ static uint32_t scale_filter_height(void *data) return (uint32_t)filter->cy_out; } +static enum gs_color_space +scale_filter_get_color_space(void *data, size_t count, + const enum gs_color_space *preferred_spaces) +{ + const enum gs_color_space potential_spaces[] = { + GS_CS_SRGB, + GS_CS_SRGB_16F, + GS_CS_709_EXTENDED, + }; + + struct scale_filter_data *const filter = data; + const enum gs_color_space source_space = obs_source_get_color_space( + obs_filter_get_parent(filter->context), + OBS_COUNTOF(potential_spaces), potential_spaces); + + enum gs_color_space space = source_space; + for (size_t i = 0; i < count; ++i) { + space = preferred_spaces[i]; + if (space == source_space) + break; + } + + return space; +} + struct obs_source_info scale_filter = { .id = "scale_filter", .type = OBS_SOURCE_TYPE_FILTER, @@ -439,4 +611,5 @@ struct obs_source_info scale_filter = { .get_defaults = scale_filter_defaults, .get_width = scale_filter_width, .get_height = scale_filter_height, + .video_get_color_space = scale_filter_get_color_space, };