From 9967a6ebf08f27a6519cffd04b1fa5563041c3e9 Mon Sep 17 00:00:00 2001 From: Michael Fabian Dirks Date: Thu, 6 Jul 2017 06:02:41 +0200 Subject: [PATCH] filter-blur: Add Color Format option This option allows applying the blur to other color formats such as YUV. Bilateral Blur benefits the most from this, resulting in smoother images at lower kernel sizes. --- data/locale/en-US.ini | 2 + source/filter-blur.cpp | 117 +++++++++++++++++++++++++++++++++++++++-- source/filter-blur.h | 7 +++ 3 files changed, 122 insertions(+), 4 deletions(-) diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index d516de42..775e9524 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -41,3 +41,5 @@ Filter.Blur.Type.Bilateral="Bilateral" Filter.Blur.Size="Size (Pixel)" Filter.Blur.Bilateral.Smoothing="Smoothing" Filter.Blur.Bilateral.Sharpness="Sharpness" +Filter.Blur.Advanced="Advanced" +Filter.Blur.Avanced.ColorFormat="Color Format" \ No newline at end of file diff --git a/source/filter-blur.cpp b/source/filter-blur.cpp index 5e013147..351f0032 100644 --- a/source/filter-blur.cpp +++ b/source/filter-blur.cpp @@ -29,7 +29,12 @@ extern "C" { #pragma warning (pop) } -static gs_effect_t *g_boxBlurEffect, *g_gaussianBlurEffect, *g_bilateralBlurEffect; +enum ColorFormat : uint64_t { + RGB, + YUV, // 701 +}; + +static gs_effect_t *g_boxBlurEffect, *g_gaussianBlurEffect, *g_bilateralBlurEffect, *g_colorConversionEffect; Filter::Blur::Blur() { memset(&sourceInfo, 0, sizeof(obs_source_info)); @@ -87,6 +92,18 @@ Filter::Blur::Blur() { PLOG_ERROR(" Loading bilateral blur effect failed with unspecified error."); } } + { + char* loadError = nullptr; + char* file = obs_module_file("effects/color-conversion.effect"); + g_colorConversionEffect = gs_effect_create_from_file(file, &loadError); + bfree(file); + if (loadError != nullptr) { + PLOG_ERROR(" Loading color conversion effect failed with error(s): %s", loadError); + bfree(loadError); + } else if (!g_colorConversionEffect) { + PLOG_ERROR(" Loading color conversion effect failed with unspecified error."); + } + } obs_leave_graphics(); if (g_boxBlurEffect && g_gaussianBlurEffect && g_bilateralBlurEffect && g_colorConversionEffect) @@ -95,6 +112,7 @@ Filter::Blur::Blur() { Filter::Blur::~Blur() { obs_enter_graphics(); + gs_effect_destroy(g_colorConversionEffect); gs_effect_destroy(g_bilateralBlurEffect); gs_effect_destroy(g_gaussianBlurEffect); gs_effect_destroy(g_boxBlurEffect); @@ -112,6 +130,10 @@ void Filter::Blur::get_defaults(obs_data_t *data) { // Bilateral Only obs_data_set_default_double(data, P_FILTER_BLUR_BILATERAL_SMOOTHING, 50.0); obs_data_set_default_double(data, P_FILTER_BLUR_BILATERAL_SHARPNESS, 90.0); + + // Advanced + obs_data_set_default_bool(data, P_FILTER_BLUR_ADVANCED, false); + obs_data_set_default_int(data, P_FILTER_BLUR_ADVANCED_COLORFORMAT, ColorFormat::RGB); } obs_properties_t * Filter::Blur::get_properties(void *) { @@ -132,6 +154,7 @@ obs_properties_t * Filter::Blur::get_properties(void *) { p = obs_properties_add_int_slider(pr, P_FILTER_BLUR_SIZE, P_TRANSLATE(P_FILTER_BLUR_SIZE), 1, 25, 1); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_FILTER_BLUR_SIZE))); + obs_property_set_modified_callback(p, modified_properties); // Bilateral Only p = obs_properties_add_float_slider(pr, P_FILTER_BLUR_BILATERAL_SMOOTHING, @@ -140,7 +163,22 @@ obs_properties_t * Filter::Blur::get_properties(void *) { p = obs_properties_add_float_slider(pr, P_FILTER_BLUR_BILATERAL_SHARPNESS, P_TRANSLATE(P_FILTER_BLUR_BILATERAL_SHARPNESS), 0, 99.99, 0.01); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_FILTER_BLUR_BILATERAL_SHARPNESS))); - + + // Advanced + p = obs_properties_add_bool(pr, P_FILTER_BLUR_ADVANCED, P_TRANSLATE(P_FILTER_BLUR_ADVANCED)); + obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_FILTER_BLUR_ADVANCED))); + obs_property_set_modified_callback(p, modified_properties); + + p = obs_properties_add_list(pr, P_FILTER_BLUR_ADVANCED_COLORFORMAT, + P_TRANSLATE(P_FILTER_BLUR_ADVANCED_COLORFORMAT), + obs_combo_type::OBS_COMBO_TYPE_LIST, obs_combo_format::OBS_COMBO_FORMAT_INT); + obs_property_set_long_description(p, + P_TRANSLATE(P_DESC(P_FILTER_BLUR_ADVANCED_COLORFORMAT))); + obs_property_list_add_int(p, "RGB", + ColorFormat::RGB); + obs_property_list_add_int(p, "YUV", + ColorFormat::YUV); + return pr; } @@ -163,6 +201,14 @@ bool Filter::Blur::modified_properties(obs_properties_t *pr, obs_property_t *, o obs_property_set_visible(obs_properties_get(pr, P_FILTER_BLUR_BILATERAL_SHARPNESS), showBilateral); + // Advanced + bool showAdvanced = false; + if (obs_data_get_bool(d, P_FILTER_BLUR_ADVANCED)) + showAdvanced = true; + + obs_property_set_visible(obs_properties_get(pr, P_FILTER_BLUR_ADVANCED_COLORFORMAT), + showAdvanced); + return true; } @@ -249,6 +295,9 @@ void Filter::Blur::Instance::update(obs_data_t *data) { // Bilateral Blur m_bilateralSmoothing = obs_data_get_double(data, P_FILTER_BLUR_BILATERAL_SMOOTHING) / 100.0; m_bilateralSharpness = obs_data_get_double(data, P_FILTER_BLUR_BILATERAL_SHARPNESS) / 100.0; + + // Advanced + m_colorFormat = obs_data_get_int(data, P_FILTER_BLUR_ADVANCED_COLORFORMAT); } uint32_t Filter::Blur::Instance::get_width() { @@ -338,7 +387,59 @@ void Filter::Blur::Instance::video_render(gs_effect_t *effect) { } #pragma endregion Source To Texture + // Conversion + if (m_colorFormat == ColorFormat::YUV) { + gs_texrender_reset(m_secondaryRT); + if (!gs_texrender_begin(m_secondaryRT, baseW, baseH)) { + PLOG_ERROR(" Failed to set up base texture."); + obs_source_skip_video_filter(m_source); + return; + } else { + gs_ortho(0, (float)baseW, 0, (float)baseH, -1, 1); + // Clear to Black + vec4 black; + vec4_zero(&black); + gs_clear(GS_CLEAR_COLOR | GS_CLEAR_DEPTH, &black, 0, 0); + + // Set up camera stuff + gs_set_cull_mode(GS_NEITHER); + gs_reset_blend_state(); + gs_blend_function_separate( + gs_blend_type::GS_BLEND_ONE, + gs_blend_type::GS_BLEND_ZERO, + gs_blend_type::GS_BLEND_ONE, + gs_blend_type::GS_BLEND_ZERO); + gs_enable_depth_test(false); + gs_enable_stencil_test(false); + gs_enable_stencil_write(false); + gs_enable_color(true, true, true, true); + + gs_eparam_t* param = gs_effect_get_param_by_name(g_colorConversionEffect, "image"); + if (!param) { + PLOG_ERROR(" Failed to set image param."); + failed = true; + } else { + gs_effect_set_texture(param, sourceTexture); + } + while (gs_effect_loop(g_colorConversionEffect, "RGBToYUV")) { + gs_draw_sprite(sourceTexture, 0, baseW, baseH); + } + gs_texrender_end(m_secondaryRT); + } + + if (failed) { + obs_source_skip_video_filter(m_source); + return; + } + + sourceTexture = gs_texrender_get_texture(m_secondaryRT); + if (!sourceTexture) { + PLOG_ERROR(" Failed to get source texture."); + obs_source_skip_video_filter(m_source); + return; + } + } gs_texture_t *blurred = blur_render(sourceTexture, baseW, baseH); if (blurred == nullptr) { @@ -348,14 +449,22 @@ void Filter::Blur::Instance::video_render(gs_effect_t *effect) { // Draw final effect { - gs_eparam_t* param = gs_effect_get_param_by_name(defaultEffect, "image"); + gs_effect_t* finalEffect = defaultEffect; + const char* technique = "Draw"; + + if (m_colorFormat == ColorFormat::YUV) { + finalEffect = g_colorConversionEffect; + technique = "YUVToRGB"; + } + + gs_eparam_t* param = gs_effect_get_param_by_name(finalEffect, "image"); if (!param) { PLOG_ERROR(" Failed to set image param."); failed = true; } else { gs_effect_set_texture(param, blurred); } - while (gs_effect_loop(defaultEffect, "Draw")) { + while (gs_effect_loop(finalEffect, technique)) { gs_draw_sprite(blurred, 0, baseW, baseH); } } diff --git a/source/filter-blur.h b/source/filter-blur.h index f8098f7d..5d6d0c40 100644 --- a/source/filter-blur.h +++ b/source/filter-blur.h @@ -32,6 +32,10 @@ #define P_FILTER_BLUR_BILATERAL_SMOOTHING "Filter.Blur.Bilateral.Smoothing" #define P_FILTER_BLUR_BILATERAL_SHARPNESS "Filter.Blur.Bilateral.Sharpness" +// Advanced +#define P_FILTER_BLUR_ADVANCED "Filter.Blur.Advanced" +#define P_FILTER_BLUR_ADVANCED_COLORFORMAT "Filter.Blur.Avanced.ColorFormat" + namespace Filter { class Blur { public: @@ -98,6 +102,9 @@ namespace Filter { // Bilateral double_t m_bilateralSmoothing; double_t m_bilateralSharpness; + + // Advanced + uint64_t m_colorFormat; }; }; }