Browse Source

Merge pull request #1685 from DDRBoxman/luma

obs-filters: Add luma key filter
Jim 6 years ago
parent
commit
397f3733cf

+ 2 - 1
plugins/obs-filters/CMakeLists.txt

@@ -51,7 +51,8 @@ set(obs-filters_SOURCES
 	invert-audio-polarity.c
 	compressor-filter.c
 	limiter-filter.c
-	expander-filter.c)
+	expander-filter.c
+	luma-key-filter.c)
 
 add_library(obs-filters MODULE
 	${obs-filters_SOURCES}

+ 5 - 0
plugins/obs-filters/data/locale/en-US.ini

@@ -93,3 +93,8 @@ Expander.None="None"
 Expander.Presets="Presets"
 Expander.Presets.Expander="Expander"
 Expander.Presets.Gate="Gate"
+LumaKeyFilter="Luma Key"
+Luma.LumaMax="Luma Max"
+Luma.LumaMin="Luma Min"
+Luma.LumaMaxSmooth="Luma Max Smooth"
+Luma.LumaMinSmooth="Luma Min Smooth"

+ 51 - 0
plugins/obs-filters/data/luma_key_filter.effect

@@ -0,0 +1,51 @@
+uniform float4x4 ViewProj;
+uniform texture2d image;
+
+uniform float lumaMax;
+uniform float lumaMin;
+uniform float lumaMaxSmooth;
+uniform float lumaMinSmooth;
+
+sampler_state textureSampler {
+	Filter    = Linear;
+	AddressU  = Clamp;
+	AddressV  = Clamp;
+};
+
+struct VertData {
+	float4 pos : POSITION;
+	float2 uv  : TEXCOORD0;
+};
+
+VertData VSDefault(VertData v_in)
+{
+	VertData vert_out;
+	vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj);
+	vert_out.uv  = v_in.uv;
+	return vert_out;
+}
+
+float4 PSALumaKeyRGBA(VertData v_in) : TARGET
+{
+	float4 rgba = image.Sample(textureSampler, v_in.uv);
+
+	float4 lumaCoef = float4(0.2989, 0.5870, 0.1140, 0.0);
+
+	float luminance = dot(rgba, lumaCoef);
+
+	float clo = smoothstep(lumaMin, lumaMin + lumaMinSmooth, luminance);
+	float chi = 1. - smoothstep(lumaMax - lumaMaxSmooth, lumaMax, luminance);
+
+	float amask = clo * chi;
+
+	return float4(rgba.rgb, amask);
+}
+
+technique Draw
+{
+	pass
+	{
+		vertex_shader = VSDefault(v_in);
+		pixel_shader  = PSALumaKeyRGBA(v_in);
+	}
+}

+ 153 - 0
plugins/obs-filters/luma-key-filter.c

@@ -0,0 +1,153 @@
+#include <obs-module.h>
+
+#define SETTING_LUMA_MAX           "luma_max"
+#define SETTING_LUMA_MIN           "luma_min"
+#define SETTING_LUMA_MAX_SMOOTH    "luma_max_smooth"
+#define SETTING_LUMA_MIN_SMOOTH    "luma_min_smooth"
+
+#define TEXT_LUMA_MAX           obs_module_text("Luma.LumaMax")
+#define TEXT_LUMA_MIN           obs_module_text("Luma.LumaMin")
+#define TEXT_LUMA_MAX_SMOOTH    obs_module_text("Luma.LumaMaxSmooth")
+#define TEXT_LUMA_MIN_SMOOTH    obs_module_text("Luma.LumaMinSmooth")
+
+struct luma_key_filter_data {
+	obs_source_t    *context;
+
+	gs_effect_t     *effect;
+
+	gs_eparam_t     *luma_max_param;
+	gs_eparam_t     *luma_min_param;
+	gs_eparam_t     *luma_max_smooth_param;
+	gs_eparam_t     *luma_min_smooth_param;
+
+	float           luma_max;
+	float           luma_min;
+	float           luma_max_smooth;
+	float           luma_min_smooth;
+};
+
+static const char *luma_key_name(void *unused)
+{
+	UNUSED_PARAMETER(unused);
+	return obs_module_text("LumaKeyFilter");
+}
+
+static void luma_key_update(void *data, obs_data_t *settings)
+{
+	struct luma_key_filter_data *filter = data;
+
+	double lumaMax = obs_data_get_double(settings, SETTING_LUMA_MAX);
+	double lumaMin = obs_data_get_double(settings, SETTING_LUMA_MIN);
+	double lumaMaxSmooth = obs_data_get_double(settings, SETTING_LUMA_MAX_SMOOTH);
+	double lumaMinSmooth = obs_data_get_double(settings, SETTING_LUMA_MIN_SMOOTH);
+
+	filter->luma_max = (float)lumaMax;
+	filter->luma_min = (float)lumaMin;
+	filter->luma_max_smooth = (float)lumaMaxSmooth;
+	filter->luma_min_smooth = (float)lumaMinSmooth;
+}
+
+static void luma_key_destroy(void *data)
+{
+	struct luma_key_filter_data *filter = data;
+
+	if (filter->effect) {
+		obs_enter_graphics();
+		gs_effect_destroy(filter->effect);
+		obs_leave_graphics();
+	}
+
+	bfree(data);
+}
+
+static void *luma_key_create(obs_data_t *settings, obs_source_t *context)
+{
+	struct luma_key_filter_data *filter =
+			bzalloc(sizeof(struct luma_key_filter_data));
+	char *effect_path = obs_module_file("luma_key_filter.effect");
+
+	filter->context = context;
+
+	obs_enter_graphics();
+
+	filter->effect = gs_effect_create_from_file(effect_path, NULL);
+	if (filter->effect) {
+		filter->luma_max_param = gs_effect_get_param_by_name(
+				filter->effect, "lumaMax");
+		filter->luma_min_param = gs_effect_get_param_by_name(
+				filter->effect, "lumaMin");
+		filter->luma_max_smooth_param = gs_effect_get_param_by_name(
+				filter->effect, "lumaMaxSmooth");
+		filter->luma_min_smooth_param = gs_effect_get_param_by_name(
+				filter->effect, "lumaMinSmooth");
+	}
+
+	obs_leave_graphics();
+
+	bfree(effect_path);
+
+	if (!filter->effect) {
+		luma_key_destroy(filter);
+		return NULL;
+	}
+
+	luma_key_update(filter, settings);
+	return filter;
+}
+
+static void luma_key_render(void *data, gs_effect_t *effect)
+{
+	struct luma_key_filter_data *filter = data;
+
+	if (!obs_source_process_filter_begin(filter->context, GS_RGBA,
+			 OBS_ALLOW_DIRECT_RENDERING))
+		return;
+
+	gs_effect_set_float(filter->luma_max_param, filter->luma_max);
+	gs_effect_set_float(filter->luma_min_param, filter->luma_min);
+	gs_effect_set_float(filter->luma_max_smooth_param, filter->luma_max_smooth);
+	gs_effect_set_float(filter->luma_min_smooth_param, filter->luma_min_smooth);
+
+	obs_source_process_filter_end(filter->context, filter->effect, 0, 0);
+
+	UNUSED_PARAMETER(effect);
+}
+
+static obs_properties_t *luma_key_properties(void *data)
+{
+	obs_properties_t *props = obs_properties_create();
+
+	obs_properties_add_float_slider(props, SETTING_LUMA_MAX,
+			TEXT_LUMA_MAX, 0, 1, 0.01);
+	obs_properties_add_float_slider(props, SETTING_LUMA_MAX_SMOOTH,
+			TEXT_LUMA_MAX_SMOOTH, 0, 1, 0.01);
+	obs_properties_add_float_slider(props, SETTING_LUMA_MIN,
+			TEXT_LUMA_MIN, 0, 1, 0.01);
+	obs_properties_add_float_slider(props, SETTING_LUMA_MIN_SMOOTH,
+			TEXT_LUMA_MIN_SMOOTH, 0, 1, 0.01);
+
+	UNUSED_PARAMETER(data);
+	return props;
+}
+
+static void luma_key_defaults(obs_data_t *settings)
+{
+	obs_data_set_default_double(settings, SETTING_LUMA_MAX, 1.0);
+	obs_data_set_default_double(settings, SETTING_LUMA_MIN, 0.0);
+	obs_data_set_default_double(settings, SETTING_LUMA_MAX_SMOOTH, 0.0);
+	obs_data_set_default_double(settings, SETTING_LUMA_MIN_SMOOTH, 0.0);
+}
+
+
+struct obs_source_info luma_key_filter = {
+	.id                            = "luma_key_filter",
+	.type                          = OBS_SOURCE_TYPE_FILTER,
+	.output_flags                  = OBS_SOURCE_VIDEO,
+	.get_name                      = luma_key_name,
+	.create                        = luma_key_create,
+	.destroy                       = luma_key_destroy,
+	.video_render                  = luma_key_render,
+	.update                        = luma_key_update,
+	.get_properties                = luma_key_properties,
+	.get_defaults                  = luma_key_defaults
+};

+ 2 - 0
plugins/obs-filters/obs-filters.c

@@ -28,6 +28,7 @@ extern struct obs_source_info noise_gate_filter;
 extern struct obs_source_info compressor_filter;
 extern struct obs_source_info limiter_filter;
 extern struct obs_source_info expander_filter;
+extern struct obs_source_info luma_key_filter;
 
 bool obs_module_load(void)
 {
@@ -51,5 +52,6 @@ bool obs_module_load(void)
 	obs_register_source(&compressor_filter);
 	obs_register_source(&limiter_filter);
 	obs_register_source(&expander_filter);
+	obs_register_source(&luma_key_filter);
 	return true;
 }