3 #include "blurwindow.h"
20 BlurConfig::BlurConfig()
28 int BlurConfig::equivalent(BlurConfig &that)
30 return (vertical == that.vertical &&
31 horizontal == that.horizontal &&
32 radius == that.radius &&
39 void BlurConfig::copy_from(BlurConfig &that)
41 vertical = that.vertical;
42 horizontal = that.horizontal;
50 void BlurConfig::interpolate(BlurConfig &prev,
54 int64_t current_frame)
56 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
57 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
60 //printf("BlurConfig::interpolate %d %d %d\n", prev_frame, next_frame, current_frame);
61 this->vertical = (int)(prev.vertical * prev_scale + next.vertical * next_scale);
62 this->horizontal = (int)(prev.horizontal * prev_scale + next.horizontal * next_scale);
63 this->radius = (int)(prev.radius * prev_scale + next.radius * next_scale);
75 REGISTER_PLUGIN(BlurMain)
84 BlurMain::BlurMain(PluginServer *server)
85 : PluginVClient(server)
91 PLUGIN_CONSTRUCTOR_MACRO
96 //printf("BlurMain::~BlurMain 1\n");
97 PLUGIN_DESTRUCTOR_MACRO
102 for(int i = 0; i < (get_project_smp() + 1); i++)
108 char* BlurMain::plugin_title() { return N_("Blur"); }
109 int BlurMain::is_realtime() { return 1; }
112 NEW_PICON_MACRO(BlurMain)
114 SHOW_GUI_MACRO(BlurMain, BlurThread)
116 SET_STRING_MACRO(BlurMain)
118 RAISE_WINDOW_MACRO(BlurMain)
120 LOAD_CONFIGURATION_MACRO(BlurMain, BlurConfig)
125 int BlurMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
128 unsigned char **input_rows, **output_rows;
130 this->input = input_ptr;
131 this->output = output_ptr;
132 need_reconfigure |= load_configuration();
135 //printf("BlurMain::process_realtime 1 %d %d\n", need_reconfigure, config.radius);
138 int y1, y2, y_increment;
142 engine = new BlurEngine*[(get_project_smp() + 1)];
143 for(int i = 0; i < (get_project_smp() + 1); i++)
145 engine[i] = new BlurEngine(this,
146 input->get_h() * i / (get_project_smp() + 1),
147 input->get_h() * (i + 1) / (get_project_smp() + 1));
152 for(i = 0; i < (get_project_smp() + 1); i++)
153 engine[i]->reconfigure();
154 need_reconfigure = 0;
159 (temp->get_w() != input_ptr->get_w() ||
160 temp->get_h() != input_ptr->get_h()))
170 input_ptr->get_color_model());
172 input_rows = input_ptr->get_rows();
173 output_rows = output_ptr->get_rows();
175 if(config.radius < 2 ||
176 (!config.vertical && !config.horizontal))
178 // Data never processed so copy if necessary
179 if(input_rows[0] != output_rows[0])
181 output_ptr->copy_from(input_ptr);
188 // Can't blur recursively. Need to blur vertically to a temp and
189 // horizontally to the output in 2 discrete passes.
190 for(i = 0; i < (get_project_smp() + 1); i++)
192 engine[i]->start_process_frame(output_ptr, input_ptr);
195 for(i = 0; i < (get_project_smp() + 1); i++)
197 engine[i]->wait_process_frame();
205 void BlurMain::update_gui()
209 load_configuration();
210 thread->window->lock_window();
211 thread->window->horizontal->update(config.horizontal);
212 thread->window->vertical->update(config.vertical);
213 thread->window->radius->update(config.radius);
214 thread->window->a->update(config.a);
215 thread->window->r->update(config.r);
216 thread->window->g->update(config.g);
217 thread->window->b->update(config.b);
218 thread->window->unlock_window();
223 int BlurMain::load_defaults()
225 char directory[1024], string[1024];
226 // set the default directory
227 sprintf(directory, "%sblur.rc", BCASTDIR);
230 defaults = new BC_Hash(directory);
233 config.vertical = defaults->get("VERTICAL", config.vertical);
234 config.horizontal = defaults->get("HORIZONTAL", config.horizontal);
235 config.radius = defaults->get("RADIUS", config.radius);
236 config.r = defaults->get("R", config.r);
237 config.g = defaults->get("G", config.g);
238 config.b = defaults->get("B", config.b);
239 config.a = defaults->get("A", config.a);
244 int BlurMain::save_defaults()
246 defaults->update("VERTICAL", config.vertical);
247 defaults->update("HORIZONTAL", config.horizontal);
248 defaults->update("RADIUS", config.radius);
249 defaults->update("R", config.r);
250 defaults->update("G", config.g);
251 defaults->update("B", config.b);
252 defaults->update("A", config.a);
259 void BlurMain::save_data(KeyFrame *keyframe)
263 // cause data to be stored directly in text
264 output.set_shared_string(keyframe->data, MESSAGESIZE);
265 output.tag.set_title("BLUR");
266 output.tag.set_property("VERTICAL", config.vertical);
267 output.tag.set_property("HORIZONTAL", config.horizontal);
268 output.tag.set_property("RADIUS", config.radius);
269 output.tag.set_property("R", config.r);
270 output.tag.set_property("G", config.g);
271 output.tag.set_property("B", config.b);
272 output.tag.set_property("A", config.a);
274 output.terminate_string();
277 void BlurMain::read_data(KeyFrame *keyframe)
281 input.set_shared_string(keyframe->data, strlen(keyframe->data));
287 result = input.read_tag();
291 if(input.tag.title_is("BLUR"))
293 config.vertical = input.tag.get_property("VERTICAL", config.vertical);
294 config.horizontal = input.tag.get_property("HORIZONTAL", config.horizontal);
295 config.radius = input.tag.get_property("RADIUS", config.radius);
296 //printf("BlurMain::read_data 1 %d %d %s\n", get_source_position(), keyframe->position, keyframe->data);
297 config.r = input.tag.get_property("R", config.r);
298 config.g = input.tag.get_property("G", config.g);
299 config.b = input.tag.get_property("B", config.b);
300 config.a = input.tag.get_property("A", config.a);
314 BlurEngine::BlurEngine(BlurMain *plugin, int start_out, int end_out)
317 int size = plugin->input->get_w() > plugin->input->get_h() ?
318 plugin->input->get_w() : plugin->input->get_h();
319 this->plugin = plugin;
320 this->start_out = start_out;
321 this->end_out = end_out;
323 val_p = new pixel_f[size];
324 val_m = new pixel_f[size];
325 src = new pixel_f[size];
326 dst = new pixel_f[size];
332 BlurEngine::~BlurEngine()
339 int BlurEngine::start_process_frame(VFrame *output, VFrame *input)
341 this->output = output;
347 int BlurEngine::wait_process_frame()
353 void BlurEngine::run()
364 output_lock.unlock();
368 start_in = start_out - plugin->config.radius;
369 end_in = end_out + plugin->config.radius;
370 if(start_in < 0) start_in = 0;
371 if(end_in > plugin->input->get_h()) end_in = plugin->input->get_h();
372 strip_size = end_in - start_in;
373 color_model = input->get_color_model();
374 int w = input->get_w();
375 int h = input->get_h();
381 #define BLUR(type, max, components) \
383 type **input_rows = (type **)input->get_rows(); \
384 type **output_rows = (type **)output->get_rows(); \
385 type **current_input = input_rows; \
386 type **current_output = output_rows; \
389 if(plugin->config.vertical) \
391 /* Vertical pass */ \
392 if(plugin->config.horizontal) \
394 current_output = (type **)plugin->temp->get_rows(); \
397 for(j = 0; j < w; j++) \
399 bzero(val_p, sizeof(pixel_f) * (end_in - start_in)); \
400 bzero(val_m, sizeof(pixel_f) * (end_in - start_in)); \
402 for(l = 0, k = start_in; k < end_in; l++, k++) \
404 if(plugin->config.r) src[l].r = (float)current_input[k][j * components]; \
405 if(plugin->config.g) src[l].g = (float)current_input[k][j * components + 1]; \
406 if(plugin->config.b) src[l].b = (float)current_input[k][j * components + 2]; \
407 if(components == 4) \
408 if(plugin->config.a) src[l].a = (float)current_input[k][j * components + 3]; \
411 if(components == 4) \
412 blur_strip4(strip_size); \
414 blur_strip3(strip_size); \
416 for(l = start_out - start_in, k = start_out; k < end_out; l++, k++) \
418 if(plugin->config.r) current_output[k][j * components] = (type)dst[l].r; \
419 if(plugin->config.g) current_output[k][j * components + 1] = (type)dst[l].g; \
420 if(plugin->config.b) current_output[k][j * components + 2] = (type)dst[l].b; \
421 if(components == 4) \
422 if(plugin->config.a) current_output[k][j * components + 3] = (type)dst[l].a; \
426 current_input = current_output; \
427 current_output = output_rows; \
431 if(plugin->config.horizontal) \
433 /* Horizontal pass */ \
434 for(j = start_out; j < end_out; j++) \
436 bzero(val_p, sizeof(pixel_f) * w); \
437 bzero(val_m, sizeof(pixel_f) * w); \
439 for(k = 0; k < w; k++) \
441 if(plugin->config.r) src[k].r = (float)current_input[j][k * components]; \
442 if(plugin->config.g) src[k].g = (float)current_input[j][k * components + 1]; \
443 if(plugin->config.b) src[k].b = (float)current_input[j][k * components + 2]; \
444 if(components == 4) \
445 if(plugin->config.a) src[k].a = (float)current_input[j][k * components + 3]; \
448 if(components == 4) \
453 for(k = 0; k < w; k++) \
455 if(plugin->config.r) current_output[j][k * components] = (type)dst[k].r; \
456 if(plugin->config.g) current_output[j][k * components + 1] = (type)dst[k].g; \
457 if(plugin->config.b) current_output[j][k * components + 2] = (type)dst[k].b; \
458 if(components == 4) \
459 if(plugin->config.a) current_output[j][k * components + 3] = (type)dst[k].a; \
471 BLUR(unsigned char, 0xff, 3);
478 BLUR(unsigned char, 0xff, 4);
485 BLUR(uint16_t, 0xffff, 3);
487 case BC_RGBA16161616:
488 case BC_YUVA16161616:
489 BLUR(uint16_t, 0xffff, 4);
493 output_lock.unlock();
497 int BlurEngine::reconfigure()
499 std_dev = sqrt(-(double)(plugin->config.radius * plugin->config.radius) /
500 (2 * log (1.0 / 255.0)));
504 int BlurEngine::get_constants()
510 div = sqrt(2 * M_PI) * std_dev;
511 constants[0] = -1.783 / std_dev;
512 constants[1] = -1.723 / std_dev;
513 constants[2] = 0.6318 / std_dev;
514 constants[3] = 1.997 / std_dev;
515 constants[4] = 1.6803 / div;
516 constants[5] = 3.735 / div;
517 constants[6] = -0.6803 / div;
518 constants[7] = -0.2598 / div;
520 n_p[0] = constants[4] + constants[6];
521 n_p[1] = exp(constants[1]) *
522 (constants[7] * sin(constants[3]) -
523 (constants[6] + 2 * constants[4]) * cos(constants[3])) +
525 (constants[5] * sin(constants[2]) -
526 (2 * constants[6] + constants[4]) * cos(constants[2]));
528 n_p[2] = 2 * exp(constants[0] + constants[1]) *
529 ((constants[4] + constants[6]) * cos(constants[3]) *
530 cos(constants[2]) - constants[5] *
531 cos(constants[3]) * sin(constants[2]) -
532 constants[7] * cos(constants[2]) * sin(constants[3])) +
533 constants[6] * exp(2 * constants[0]) +
534 constants[4] * exp(2 * constants[1]);
536 n_p[3] = exp(constants[1] + 2 * constants[0]) *
537 (constants[7] * sin(constants[3]) -
538 constants[6] * cos(constants[3])) +
539 exp(constants[0] + 2 * constants[1]) *
540 (constants[5] * sin(constants[2]) - constants[4] *
545 d_p[1] = -2 * exp(constants[1]) * cos(constants[3]) -
546 2 * exp(constants[0]) * cos(constants[2]);
548 d_p[2] = 4 * cos(constants[3]) * cos(constants[2]) *
549 exp(constants[0] + constants[1]) +
550 exp(2 * constants[1]) + exp (2 * constants[0]);
552 d_p[3] = -2 * cos(constants[2]) * exp(constants[0] + 2 * constants[1]) -
553 2 * cos(constants[3]) * exp(constants[1] + 2 * constants[0]);
555 d_p[4] = exp(2 * constants[0] + 2 * constants[1]);
557 for(i = 0; i < 5; i++) d_m[i] = d_p[i];
560 for(i = 1; i <= 4; i++)
561 n_m[i] = n_p[i] - d_p[i] * n_p[0];
563 double sum_n_p, sum_n_m, sum_d;
569 for(i = 0; i < 5; i++)
576 a = sum_n_p / (1 + sum_d);
577 b = sum_n_m / (1 + sum_d);
579 for (i = 0; i < 5; i++)
581 bd_p[i] = d_p[i] * a;
582 bd_m[i] = d_m[i] * b;
587 #define BOUNDARY(x) if((x) > vmax) (x) = vmax; else if((x) < 0) (x) = 0;
589 int BlurEngine::transfer_pixels(pixel_f *src1, pixel_f *src2, pixel_f *dest, int size)
594 // printf("BlurEngine::transfer_pixels %d %d %d %d\n",
598 // plugin->config.a);
600 for(i = 0; i < size; i++)
602 sum = src1[i].r + src2[i].r;
605 sum = src1[i].g + src2[i].g;
608 sum = src1[i].b + src2[i].b;
611 sum = src1[i].a + src2[i].a;
619 int BlurEngine::multiply_alpha(pixel_f *row, int size)
622 register float alpha;
624 // for(i = 0; i < size; i++)
626 // alpha = (float)row[i].a / vmax;
627 // row[i].r *= alpha;
628 // row[i].g *= alpha;
629 // row[i].b *= alpha;
634 int BlurEngine::separate_alpha(pixel_f *row, int size)
637 register float alpha;
638 register float result;
640 // for(i = 0; i < size; i++)
642 // if(row[i].a > 0 && row[i].a < vmax)
644 // alpha = (float)row[i].a / vmax;
645 // result = (float)row[i].r / alpha;
646 // row[i].r = (result > vmax ? vmax : result);
647 // result = (float)row[i].g / alpha;
648 // row[i].g = (result > vmax ? vmax : result);
649 // result = (float)row[i].b / alpha;
650 // row[i].b = (result > vmax ? vmax : result);
656 int BlurEngine::blur_strip3(int &size)
658 multiply_alpha(src, size);
661 sp_m = src + size - 1;
663 vm = val_m + size - 1;
669 for(int k = 0; k < size; k++)
671 terms = (k < 4) ? k : 4;
672 for(l = 0; l <= terms; l++)
676 vp->r += n_p[l] * sp_p[-l].r - d_p[l] * vp[-l].r;
677 vm->r += n_m[l] * sp_m[l].r - d_m[l] * vm[l].r;
681 vp->g += n_p[l] * sp_p[-l].g - d_p[l] * vp[-l].g;
682 vm->g += n_m[l] * sp_m[l].g - d_m[l] * vm[l].g;
686 vp->b += n_p[l] * sp_p[-l].b - d_p[l] * vp[-l].b;
687 vm->b += n_m[l] * sp_m[l].b - d_m[l] * vm[l].b;
694 vp->r += (n_p[l] - bd_p[l]) * initial_p.r;
695 vm->r += (n_m[l] - bd_m[l]) * initial_m.r;
699 vp->g += (n_p[l] - bd_p[l]) * initial_p.g;
700 vm->g += (n_m[l] - bd_m[l]) * initial_m.g;
704 vp->b += (n_p[l] - bd_p[l]) * initial_p.b;
705 vm->b += (n_m[l] - bd_m[l]) * initial_m.b;
713 transfer_pixels(val_p, val_m, dst, size);
714 separate_alpha(dst, size);
719 int BlurEngine::blur_strip4(int &size)
721 multiply_alpha(src, size);
724 sp_m = src + size - 1;
726 vm = val_m + size - 1;
732 for(int k = 0; k < size; k++)
734 terms = (k < 4) ? k : 4;
736 for(l = 0; l <= terms; l++)
740 vp->r += n_p[l] * sp_p[-l].r - d_p[l] * vp[-l].r;
741 vm->r += n_m[l] * sp_m[l].r - d_m[l] * vm[l].r;
745 vp->g += n_p[l] * sp_p[-l].g - d_p[l] * vp[-l].g;
746 vm->g += n_m[l] * sp_m[l].g - d_m[l] * vm[l].g;
750 vp->b += n_p[l] * sp_p[-l].b - d_p[l] * vp[-l].b;
751 vm->b += n_m[l] * sp_m[l].b - d_m[l] * vm[l].b;
755 vp->a += n_p[l] * sp_p[-l].a - d_p[l] * vp[-l].a;
756 vm->a += n_m[l] * sp_m[l].a - d_m[l] * vm[l].a;
764 vp->r += (n_p[l] - bd_p[l]) * initial_p.r;
765 vm->r += (n_m[l] - bd_m[l]) * initial_m.r;
769 vp->g += (n_p[l] - bd_p[l]) * initial_p.g;
770 vm->g += (n_m[l] - bd_m[l]) * initial_m.g;
774 vp->b += (n_p[l] - bd_p[l]) * initial_p.b;
775 vm->b += (n_m[l] - bd_m[l]) * initial_m.b;
779 vp->a += (n_p[l] - bd_p[l]) * initial_p.a;
780 vm->a += (n_m[l] - bd_m[l]) * initial_m.a;
789 transfer_pixels(val_p, val_m, dst, size);
790 separate_alpha(dst, size);