filter-blur: Initial work on optimization

This commit is contained in:
Michael Fabian Dirks 2017-07-18 16:47:29 +02:00
parent 0570904c5b
commit 52c3a0171e
2 changed files with 98 additions and 12 deletions

View file

@ -29,12 +29,29 @@ extern "C" {
#pragma warning (pop) #pragma warning (pop)
} }
#include <math.h>
#include <map>
enum ColorFormat : uint64_t { enum ColorFormat : uint64_t {
RGB, RGB,
YUV, // 701 YUV, // 701
}; };
static gs_effect_t *g_boxBlurEffect, *g_gaussianBlurEffect, *g_bilateralBlurEffect, *g_colorConversionEffect; struct g_blurEffect {
gs_effect_t* effect;
std::vector<gs_texture_t*> kernels;
};
static g_blurEffect g_gaussianBlur, g_bilateralBlur;
static gs_effect_t* g_boxBlurEffect, *g_colorConversionEffect;
static size_t g_maxKernelSize = 25;
double_t gaussian1D(double_t x, double_t o) {
return (1.0 / (o * sqrt(2 * M_PI))) * exp(-(x*x) / (2 * (o*o)));
}
double_t bilateral(double_t x, double_t o) {
return 0.39894 * exp(-0.5 * (x * x) / (o * o)) / o;
}
Filter::Blur::Blur() { Filter::Blur::Blur() {
memset(&sourceInfo, 0, sizeof(obs_source_info)); memset(&sourceInfo, 0, sizeof(obs_source_info));
@ -56,6 +73,9 @@ Filter::Blur::Blur() {
sourceInfo.video_render = video_render; sourceInfo.video_render = video_render;
obs_enter_graphics(); obs_enter_graphics();
// Blur Effects
/// Box Blur
{ {
char* loadError = nullptr; char* loadError = nullptr;
char* file = obs_module_file("effects/box-blur.effect"); char* file = obs_module_file("effects/box-blur.effect");
@ -68,30 +88,92 @@ Filter::Blur::Blur() {
PLOG_ERROR("<filter-blur> Loading box-blur effect failed with unspecified error."); PLOG_ERROR("<filter-blur> Loading box-blur effect failed with unspecified error.");
} }
} }
/// Gaussian Blur
{ {
gs_effect_t* effect;
char* loadError = nullptr; char* loadError = nullptr;
char* file = obs_module_file("effects/gaussian-blur.effect"); char* file = obs_module_file("effects/gaussian-blur.effect");
g_gaussianBlurEffect = gs_effect_create_from_file(file, &loadError); effect = gs_effect_create_from_file(file, &loadError);
bfree(file); bfree(file);
if (loadError != nullptr) { if (loadError != nullptr) {
PLOG_ERROR("<filter-blur> Loading gaussian blur effect failed with error(s): %s", loadError); PLOG_ERROR("<filter-blur> Loading gaussian blur effect failed with error(s): %s", loadError);
bfree(loadError); bfree(loadError);
} else if (!g_gaussianBlurEffect) { } else if (!effect) {
PLOG_ERROR("<filter-blur> Loading gaussian blur effect failed with unspecified error."); PLOG_ERROR("<filter-blur> Loading gaussian blur effect failed with unspecified error.");
} else {
g_gaussianBlur.effect = effect;
g_gaussianBlur.kernels.resize(g_maxKernelSize);
std::vector<float_t> databuf;
for (size_t n = 1; n <= g_maxKernelSize; n++) {
databuf.resize(n);
// Calculate
double_t sum = 0.0;
for (size_t p = 0; p < n; p ++) {
databuf[p] = gaussian1D(p, n);
sum += databuf[p];
if (p != 0)
sum += databuf[p];
}
// Normalize
for (size_t p = 0; p < n; p++) {
databuf[p] /= sum;
}
uint8_t* data = reinterpret_cast<uint8_t*>(databuf.data());
const uint8_t** pdata = const_cast<const uint8_t**>(&data);
gs_texture_t* tex = gs_texture_create(n, 1, gs_color_format::GS_R32F, 1, pdata, 0);
if (!tex) {
PLOG_ERROR("<filter-blur> Failed to create gaussian kernel for %d width.", n);
} else {
g_gaussianBlur.kernels[n - 1] = tex;
}
}
} }
} }
/// Bilateral Blur
{ {
gs_effect_t* effect;
char* loadError = nullptr; char* loadError = nullptr;
char* file = obs_module_file("effects/bilateral-blur.effect"); char* file = obs_module_file("effects/bilateral-blur.effect");
g_bilateralBlurEffect = gs_effect_create_from_file(file, &loadError); effect = gs_effect_create_from_file(file, &loadError);
bfree(file); bfree(file);
if (loadError != nullptr) { if (loadError != nullptr) {
PLOG_ERROR("<filter-blur> Loading bilateral blur effect failed with error(s): %s", loadError); PLOG_ERROR("<filter-blur> Loading bilateral blur effect failed with error(s): %s", loadError);
bfree(loadError); bfree(loadError);
} else if (!g_bilateralBlurEffect) { } else if (!effect) {
PLOG_ERROR("<filter-blur> Loading bilateral blur effect failed with unspecified error."); PLOG_ERROR("<filter-blur> Loading bilateral blur effect failed with unspecified error.");
} else {
g_bilateralBlur.effect = effect;
g_bilateralBlur.kernels.resize(g_maxKernelSize);
std::vector<float_t> databuf;
for (size_t n = 1; n <= g_maxKernelSize; n++) {
databuf.resize(n);
// Calculate
double_t sum = 0.0;
for (size_t p = 0; p < n; p++) {
databuf[p] = gaussian1D(p, M_PI);
sum += databuf[p];
if (p != 0)
sum += databuf[p];
}
// Normalize
for (size_t p = 0; p < n; p++) {
databuf[p] /= sum;
}
uint8_t* data = reinterpret_cast<uint8_t*>(databuf.data());
const uint8_t** pdata = const_cast<const uint8_t**>(&data);
gs_texture_t* tex = gs_texture_create(n, 1, gs_color_format::GS_R32F, 1, pdata, 0);
if (!tex) {
PLOG_ERROR("<filter-blur> Failed to create bilateral kernel for %d width.", n);
} else {
g_bilateralBlur.kernels[n - 1] = tex;
}
}
} }
} }
// Color Conversion
{ {
char* loadError = nullptr; char* loadError = nullptr;
char* file = obs_module_file("effects/color-conversion.effect"); char* file = obs_module_file("effects/color-conversion.effect");
@ -104,17 +186,21 @@ Filter::Blur::Blur() {
PLOG_ERROR("<filter-blur> Loading color conversion effect failed with unspecified error."); PLOG_ERROR("<filter-blur> Loading color conversion effect failed with unspecified error.");
} }
} }
obs_leave_graphics(); obs_leave_graphics();
if (g_boxBlurEffect && g_gaussianBlurEffect && g_bilateralBlurEffect && g_colorConversionEffect) if (g_boxBlurEffect && g_gaussianBlur.effect && g_bilateralBlur.effect && g_colorConversionEffect)
obs_register_source(&sourceInfo); obs_register_source(&sourceInfo);
} }
Filter::Blur::~Blur() { Filter::Blur::~Blur() {
obs_enter_graphics(); obs_enter_graphics();
gs_effect_destroy(g_colorConversionEffect); gs_effect_destroy(g_colorConversionEffect);
gs_effect_destroy(g_bilateralBlurEffect); gs_effect_destroy(g_bilateralBlur.effect);
gs_effect_destroy(g_gaussianBlurEffect); gs_effect_destroy(g_gaussianBlur.effect);
for (size_t n = 1; n <= g_maxKernelSize; n++) {
gs_texture_destroy(g_gaussianBlur.kernels[n - 1]);
}
gs_effect_destroy(g_boxBlurEffect); gs_effect_destroy(g_boxBlurEffect);
obs_leave_graphics(); obs_leave_graphics();
} }
@ -284,10 +370,10 @@ void Filter::Blur::Instance::update(obs_data_t *data) {
m_effect = g_boxBlurEffect; m_effect = g_boxBlurEffect;
break; break;
case Filter::Blur::Type::Gaussian: case Filter::Blur::Type::Gaussian:
m_effect = g_gaussianBlurEffect; m_effect = g_gaussianBlur.effect;
break; break;
case Filter::Blur::Type::Bilateral: case Filter::Blur::Type::Bilateral:
m_effect = g_bilateralBlurEffect; m_effect = g_bilateralBlur.effect;
break; break;
} }
m_size = (uint64_t)obs_data_get_int(data, P_FILTER_BLUR_SIZE); m_size = (uint64_t)obs_data_get_int(data, P_FILTER_BLUR_SIZE);
@ -475,7 +561,7 @@ void Filter::Blur::Instance::video_render(gs_effect_t *effect) {
} }
} }
gs_texture_t* Filter::Blur::Instance::blur_render(gs_texture_t* input, size_t baseW, size_t baseH) { gs_texture_t* Filter::Blur::Instance::blur_render(gs_texture_t* input, uint32_t baseW, uint32_t baseH) {
bool failed = false; bool failed = false;
gs_texture_t *intermediate; gs_texture_t *intermediate;

View file

@ -83,7 +83,7 @@ namespace Filter {
void hide(); void hide();
void video_tick(float); void video_tick(float);
void video_render(gs_effect_t*); void video_render(gs_effect_t*);
gs_texture_t* blur_render(gs_texture_t* input, size_t baseW, size_t baseH); gs_texture_t* blur_render(gs_texture_t* input, uint32_t baseW, uint32_t baseH);
bool apply_effect_param(gs_texture_t* texture, bool apply_effect_param(gs_texture_t* texture,
float uvTexelX, float uvTexelY); float uvTexelX, float uvTexelY);