From bee5b3a2d2e1e08e8f78707b34455dc707c2e00c Mon Sep 17 00:00:00 2001 From: jp9000 Date: Sat, 21 Mar 2015 18:34:29 -0700 Subject: [PATCH] obs-filters: Add color correction filter Adds a color correction filter if one wishes to just apply gamma/constrast/brightness/opacity/color to a source. --- plugins/obs-filters/CMakeLists.txt | 1 + plugins/obs-filters/color-filter.c | 172 +++++++++++++++++++ plugins/obs-filters/data/color_filter.effect | 67 ++++++++ plugins/obs-filters/data/locale/en-US.ini | 1 + plugins/obs-filters/obs-filters.c | 2 + 5 files changed, 243 insertions(+) create mode 100644 plugins/obs-filters/color-filter.c create mode 100644 plugins/obs-filters/data/color_filter.effect diff --git a/plugins/obs-filters/CMakeLists.txt b/plugins/obs-filters/CMakeLists.txt index 1e5f5e48b..b5ab13684 100644 --- a/plugins/obs-filters/CMakeLists.txt +++ b/plugins/obs-filters/CMakeLists.txt @@ -2,6 +2,7 @@ project(obs-filters) set(obs-filters_SOURCES obs-filters.c + color-filter.c async-delay-filter.c crop-filter.c mask-filter.c) diff --git a/plugins/obs-filters/color-filter.c b/plugins/obs-filters/color-filter.c new file mode 100644 index 000000000..240f1db58 --- /dev/null +++ b/plugins/obs-filters/color-filter.c @@ -0,0 +1,172 @@ +#include +#include + +#define SETTING_COLOR "color" +#define SETTING_OPACITY "opacity" +#define SETTING_CONTRAST "contrast" +#define SETTING_BRIGHTNESS "brightness" +#define SETTING_GAMMA "gamma" + +#define TEXT_COLOR obs_module_text("Color") +#define TEXT_OPACITY obs_module_text("Opacity") +#define TEXT_CONTRAST obs_module_text("Contrast") +#define TEXT_BRIGHTNESS obs_module_text("Brightness") +#define TEXT_GAMMA obs_module_text("Gamma") + +#define MIN_CONTRAST 0.5f +#define MAX_CONTRAST 2.0f +#define MIN_BRIGHTNESS -1.0 +#define MAX_BRIGHTNESS 1.0 + +struct color_filter_data { + obs_source_t *context; + + gs_effect_t *effect; + + gs_eparam_t *color_param; + gs_eparam_t *contrast_param; + gs_eparam_t *brightness_param; + gs_eparam_t *gamma_param; + + struct vec4 color; + float contrast; + float brightness; + float gamma; +}; + +static const char *color_filter_name(void) +{ + return obs_module_text("ColorFilter"); +} + +static void color_filter_update(void *data, obs_data_t *settings) +{ + struct color_filter_data *filter = data; + uint32_t color = (uint32_t)obs_data_get_int(settings, SETTING_COLOR); + uint32_t opacity = (uint32_t)obs_data_get_int(settings, + SETTING_OPACITY); + double contrast = obs_data_get_double(settings, SETTING_CONTRAST); + double brightness = obs_data_get_double(settings, SETTING_BRIGHTNESS); + double gamma = obs_data_get_double(settings, SETTING_GAMMA); + + color &= 0xFFFFFF; + color |= ((opacity * 255) / 100) << 24; + + vec4_from_rgba(&filter->color, color); + + contrast = (contrast < 0.0) ? + (1.0 / (-contrast + 1.0)) : (contrast + 1.0); + + brightness *= 0.5; + + gamma = (gamma < 0.0) ? (-gamma + 1.0) : (1.0 / (gamma + 1.0)); + + filter->contrast = (float)contrast; + filter->brightness = (float)brightness; + filter->gamma = (float)gamma; +} + +static void color_filter_destroy(void *data) +{ + struct color_filter_data *filter = data; + + if (filter->effect) { + obs_enter_graphics(); + gs_effect_destroy(filter->effect); + obs_leave_graphics(); + } + + bfree(data); +} + +static void *color_filter_create(obs_data_t *settings, obs_source_t *context) +{ + struct color_filter_data *filter = + bzalloc(sizeof(struct color_filter_data)); + char *effect_path = obs_module_file("color_filter.effect"); + + filter->context = context; + + obs_enter_graphics(); + + filter->effect = gs_effect_create_from_file(effect_path, NULL); + if (filter) { + filter->color_param = gs_effect_get_param_by_name( + filter->effect, "color"); + filter->contrast_param = gs_effect_get_param_by_name( + filter->effect, "contrast"); + filter->brightness_param = gs_effect_get_param_by_name( + filter->effect, "brightness"); + filter->gamma_param = gs_effect_get_param_by_name( + filter->effect, "gamma"); + } + + obs_leave_graphics(); + + bfree(effect_path); + + if (!filter->effect) { + color_filter_destroy(filter); + return NULL; + } + + color_filter_update(filter, settings); + return filter; +} + +static void color_filter_render(void *data, gs_effect_t *effect) +{ + struct color_filter_data *filter = data; + + obs_source_process_filter_begin(filter->context, GS_RGBA, + OBS_ALLOW_DIRECT_RENDERING); + + gs_effect_set_vec4(filter->color_param, &filter->color); + gs_effect_set_float(filter->contrast_param, filter->contrast); + gs_effect_set_float(filter->brightness_param, filter->brightness); + gs_effect_set_float(filter->gamma_param, filter->gamma); + + obs_source_process_filter_end(filter->context, filter->effect, 0, 0); + + UNUSED_PARAMETER(effect); +} + +static obs_properties_t *color_filter_properties(void *data) +{ + obs_properties_t *props = obs_properties_create(); + + obs_properties_add_color(props, SETTING_COLOR, TEXT_COLOR); + obs_properties_add_int(props, SETTING_OPACITY, TEXT_OPACITY, + 0, 100, 1); + obs_properties_add_float_slider(props, SETTING_CONTRAST, + TEXT_CONTRAST, -1.0, 1.0, 0.01); + obs_properties_add_float_slider(props, SETTING_BRIGHTNESS, + TEXT_BRIGHTNESS, -1.0, 1.0, 0.01); + obs_properties_add_float_slider(props, SETTING_GAMMA, + TEXT_GAMMA, -1.0, 1.0, 0.01); + + UNUSED_PARAMETER(data); + return props; +} + +static void color_filter_defaults(obs_data_t *settings) +{ + obs_data_set_default_int(settings, SETTING_COLOR, 0xFFFFFF); + obs_data_set_default_int(settings, SETTING_OPACITY, 100); + obs_data_set_default_double(settings, SETTING_CONTRAST, 0.0); + obs_data_set_default_double(settings, SETTING_BRIGHTNESS, 0.0); + obs_data_set_default_double(settings, SETTING_GAMMA, 0.0); +} + +struct obs_source_info color_filter = { + .id = "color_filter", + .type = OBS_SOURCE_TYPE_FILTER, + .output_flags = OBS_SOURCE_VIDEO, + .get_name = color_filter_name, + .create = color_filter_create, + .destroy = color_filter_destroy, + .video_render = color_filter_render, + .update = color_filter_update, + .get_properties = color_filter_properties, + .get_defaults = color_filter_defaults +}; diff --git a/plugins/obs-filters/data/color_filter.effect b/plugins/obs-filters/data/color_filter.effect new file mode 100644 index 000000000..712ca4b95 --- /dev/null +++ b/plugins/obs-filters/data/color_filter.effect @@ -0,0 +1,67 @@ +uniform float4x4 ViewProj; +uniform texture2d image; +uniform float4x4 color_matrix; +uniform float3 color_range_min = {0.0, 0.0, 0.0}; +uniform float3 color_range_max = {1.0, 1.0, 1.0}; + +uniform float4 color; +uniform float contrast; +uniform float brightness; +uniform float gamma; + +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 CalcColor(float4 rgba) +{ + return float4(pow(rgba.rgb, float3(gamma, gamma, gamma)) * contrast + brightness, rgba.a); +} + +float4 PSColorFilterRGBA(VertData v_in) : TARGET +{ + float4 rgba = image.Sample(textureSampler, v_in.uv) * color; + return CalcColor(rgba); +} + +float4 PSColorFilterMatrix(VertData v_in) : TARGET +{ + float4 yuv = image.Sample(textureSampler, v_in.uv); + yuv.xyz = clamp(yuv.xyz, color_range_min, color_range_max); + float4 rgba = saturate(mul(float4(yuv.xyz, 1.0), color_matrix)) * color; + + return CalcColor(rgba); +} + +technique Draw +{ + pass + { + vertex_shader = VSDefault(v_in); + pixel_shader = PSColorFilterRGBA(v_in); + } +} + +technique DrawMatrix +{ + pass + { + vertex_shader = VSDefault(v_in); + pixel_shader = PSColorFilterMatrix(v_in); + } +} diff --git a/plugins/obs-filters/data/locale/en-US.ini b/plugins/obs-filters/data/locale/en-US.ini index 91ec6f304..34be7917d 100644 --- a/plugins/obs-filters/data/locale/en-US.ini +++ b/plugins/obs-filters/data/locale/en-US.ini @@ -1,3 +1,4 @@ +ColorFilter="Color Correction" MaskFilter="Image Mask/Blend" AsyncDelayFilter="Video Delay (Async)" CropFilter="Crop" diff --git a/plugins/obs-filters/obs-filters.c b/plugins/obs-filters/obs-filters.c index 19f366485..3ac7fe4f9 100644 --- a/plugins/obs-filters/obs-filters.c +++ b/plugins/obs-filters/obs-filters.c @@ -6,12 +6,14 @@ OBS_MODULE_USE_DEFAULT_LOCALE("obs-filters", "en-US") extern struct obs_source_info mask_filter; extern struct obs_source_info crop_filter; +extern struct obs_source_info color_filter; extern struct obs_source_info async_delay_filter; bool obs_module_load(void) { obs_register_source(&mask_filter); obs_register_source(&crop_filter); + obs_register_source(&color_filter); obs_register_source(&async_delay_filter); return true; }