3 #include "blurwindow.h"
13 #define _(String) gettext(String)
14 #define gettext_noop(String) String
15 #define N_(String) gettext_noop (String)
23 BlurConfig::BlurConfig()
31 int BlurConfig::equivalent(BlurConfig &that)
33 return (vertical == that.vertical &&
34 horizontal == that.horizontal &&
35 radius == that.radius &&
42 void BlurConfig::copy_from(BlurConfig &that)
44 vertical = that.vertical;
45 horizontal = that.horizontal;
53 void BlurConfig::interpolate(BlurConfig &prev,
57 int64_t current_frame)
59 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
60 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
63 //printf("BlurConfig::interpolate %d %d %d\n", prev_frame, next_frame, current_frame);
64 this->vertical = (int)(prev.vertical * prev_scale + next.vertical * next_scale);
65 this->horizontal = (int)(prev.horizontal * prev_scale + next.horizontal * next_scale);
66 this->radius = (int)(prev.radius * prev_scale + next.radius * next_scale);
78 REGISTER_PLUGIN(BlurMain)
87 BlurMain::BlurMain(PluginServer *server)
88 : PluginVClient(server)
94 PLUGIN_CONSTRUCTOR_MACRO
99 //printf("BlurMain::~BlurMain 1\n");
100 PLUGIN_DESTRUCTOR_MACRO
102 if(temp) delete temp;
105 for(int i = 0; i < (PluginClient::smp + 1); i++)
111 char* BlurMain::plugin_title() { return _("Blur"); }
112 int BlurMain::is_realtime() { return 1; }
115 NEW_PICON_MACRO(BlurMain)
117 SHOW_GUI_MACRO(BlurMain, BlurThread)
119 SET_STRING_MACRO(BlurMain)
121 RAISE_WINDOW_MACRO(BlurMain)
123 LOAD_CONFIGURATION_MACRO(BlurMain, BlurConfig)
128 int BlurMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
131 unsigned char **input_rows, **output_rows;
133 this->input = input_ptr;
134 this->output = output_ptr;
135 need_reconfigure |= load_configuration();
138 //printf("BlurMain::process_realtime 1 %d %d\n", need_reconfigure, config.radius);
141 int y1, y2, y_increment;
145 y_increment = input->get_h() / (smp + 1);
148 engine = new BlurEngine*[(PluginClient::smp + 1)];
149 for(int i = 0; i < (PluginClient::smp + 1); i++)
151 y2 = y1 + y_increment;
152 if(i == (PluginClient::smp + 1) - 1 &&
153 y2 < input->get_h() - 1)
154 y2 = input->get_h() - 1;
156 engine[i] = new BlurEngine(this, y1, y2);
162 for(i = 0; i < (PluginClient::smp + 1); i++)
163 engine[i]->reconfigure();
164 need_reconfigure = 0;
169 (temp->get_w() != input_ptr->get_w() ||
170 temp->get_h() != input_ptr->get_h()))
180 input_ptr->get_color_model());
182 input_rows = input_ptr->get_rows();
183 output_rows = output_ptr->get_rows();
185 if(config.radius < 2 ||
186 (!config.vertical && !config.horizontal))
188 // Data never processed so copy if necessary
189 //printf("BlurMain::process_realtime 2 %d\n", radius);
190 if(input_rows[0] != output_rows[0])
192 output_ptr->copy_from(input_ptr);
199 // Can't blur recursively. Need to blur to a temp and
200 // horizontally to the output in 2 discrete passes.
201 //printf("BlurMain::process_realtime 3 %d\n", (smp + 1));
202 for(i = 0; i < (smp + 1); i++)
204 engine[i]->start_process_frame(output_ptr, input_ptr);
207 for(i = 0; i < (smp + 1); i++)
209 engine[i]->wait_process_frame();
217 void BlurMain::update_gui()
221 load_configuration();
222 thread->window->lock_window();
223 thread->window->horizontal->update(config.horizontal);
224 thread->window->vertical->update(config.vertical);
225 thread->window->radius->update(config.radius);
226 thread->window->a->update(config.a);
227 thread->window->r->update(config.r);
228 thread->window->g->update(config.g);
229 thread->window->b->update(config.b);
230 thread->window->unlock_window();
235 int BlurMain::load_defaults()
237 char directory[1024], string[1024];
238 // set the default directory
239 sprintf(directory, "%sblur.rc", BCASTDIR);
242 defaults = new Defaults(directory);
245 config.vertical = defaults->get("VERTICAL", config.vertical);
246 config.horizontal = defaults->get("HORIZONTAL", config.horizontal);
247 config.radius = defaults->get("RADIUS", config.radius);
248 config.r = defaults->get("R", config.r);
249 config.g = defaults->get("G", config.g);
250 config.b = defaults->get("B", config.b);
251 config.a = defaults->get("A", config.a);
256 int BlurMain::save_defaults()
258 defaults->update("VERTICAL", config.vertical);
259 defaults->update("HORIZONTAL", config.horizontal);
260 defaults->update("RADIUS", config.radius);
261 defaults->update("R", config.r);
262 defaults->update("G", config.g);
263 defaults->update("B", config.b);
264 defaults->update("A", config.a);
271 void BlurMain::save_data(KeyFrame *keyframe)
275 // cause data to be stored directly in text
276 output.set_shared_string(keyframe->data, MESSAGESIZE);
277 output.tag.set_title("BLUR");
278 output.tag.set_property("VERTICAL", config.vertical);
279 output.tag.set_property("HORIZONTAL", config.horizontal);
280 output.tag.set_property("RADIUS", config.radius);
281 output.tag.set_property("R", config.r);
282 output.tag.set_property("G", config.g);
283 output.tag.set_property("B", config.b);
284 output.tag.set_property("A", config.a);
286 output.terminate_string();
289 void BlurMain::read_data(KeyFrame *keyframe)
293 input.set_shared_string(keyframe->data, strlen(keyframe->data));
299 result = input.read_tag();
303 if(input.tag.title_is("BLUR"))
305 config.vertical = input.tag.get_property("VERTICAL", config.vertical);
306 config.horizontal = input.tag.get_property("HORIZONTAL", config.horizontal);
307 config.radius = input.tag.get_property("RADIUS", config.radius);
308 //printf("BlurMain::read_data 1 %d %d %s\n", get_source_position(), keyframe->position, keyframe->data);
309 config.r = input.tag.get_property("R", config.r);
310 config.g = input.tag.get_property("G", config.g);
311 config.b = input.tag.get_property("B", config.b);
312 config.a = input.tag.get_property("A", config.a);
326 BlurEngine::BlurEngine(BlurMain *plugin, int start_out, int end_out)
329 int size = plugin->input->get_w() > plugin->input->get_h() ?
330 plugin->input->get_w() : plugin->input->get_h();
331 this->plugin = plugin;
332 this->start_out = start_out;
333 this->end_out = end_out;
335 val_p = new pixel_f[size];
336 val_m = new pixel_f[size];
337 src = new pixel_f[size];
338 dst = new pixel_f[size];
344 BlurEngine::~BlurEngine()
351 int BlurEngine::start_process_frame(VFrame *output, VFrame *input)
353 this->output = output;
359 int BlurEngine::wait_process_frame()
365 void BlurEngine::run()
375 output_lock.unlock();
379 start_in = start_out - plugin->config.radius;
380 end_in = end_out + plugin->config.radius;
381 if(start_in < 0) start_in = 0;
382 if(end_in > plugin->input->get_h()) end_in = plugin->input->get_h();
383 strip_size = end_in - start_in;
384 color_model = input->get_color_model();
385 int w = input->get_w();
386 int h = input->get_h();
392 #define BLUR(type, max, components) \
394 type **input_rows = (type **)input->get_rows(); \
395 type **output_rows = (type **)output->get_rows(); \
396 type **current_input = input_rows; \
397 type **current_output = output_rows; \
400 if(plugin->config.vertical) \
402 /* Vertical pass */ \
403 if(plugin->config.horizontal) \
405 current_output = (type **)plugin->temp->get_rows(); \
408 for(j = 0; j < w; j++) \
410 bzero(val_p, sizeof(pixel_f) * (end_in - start_in)); \
411 bzero(val_m, sizeof(pixel_f) * (end_in - start_in)); \
413 for(l = 0, k = start_in; k < end_in; l++, k++) \
415 if(plugin->config.r) src[l].r = (float)current_input[k][j * components]; \
416 if(plugin->config.g) src[l].g = (float)current_input[k][j * components + 1]; \
417 if(plugin->config.b) src[l].b = (float)current_input[k][j * components + 2]; \
418 if(components == 4) \
419 if(plugin->config.a) src[l].a = (float)current_input[k][j * components + 3]; \
422 if(components == 4) \
423 blur_strip4(strip_size); \
425 blur_strip3(strip_size); \
427 for(l = start_out - start_in, k = start_out; k < end_out; l++, k++) \
429 if(plugin->config.r) current_output[k][j * components] = (type)dst[l].r; \
430 if(plugin->config.g) current_output[k][j * components + 1] = (type)dst[l].g; \
431 if(plugin->config.b) current_output[k][j * components + 2] = (type)dst[l].b; \
432 if(components == 4) \
433 if(plugin->config.a) current_output[k][j * components + 3] = (type)dst[l].a; \
437 current_input = current_output; \
438 current_output = output_rows; \
442 if(plugin->config.horizontal) \
444 /* Horizontal pass */ \
445 for(j = start_out; j < end_out; j++) \
447 bzero(val_p, sizeof(pixel_f) * w); \
448 bzero(val_m, sizeof(pixel_f) * w); \
450 for(k = 0; k < w; k++) \
452 if(plugin->config.r) src[k].r = (float)current_input[j][k * components]; \
453 if(plugin->config.g) src[k].g = (float)current_input[j][k * components + 1]; \
454 if(plugin->config.b) src[k].b = (float)current_input[j][k * components + 2]; \
455 if(components == 4) \
456 if(plugin->config.a) src[k].a = (float)current_input[j][k * components + 3]; \
459 if(components == 4) \
464 for(k = 0; k < w; k++) \
466 if(plugin->config.r) current_output[j][k * components] = (type)dst[k].r; \
467 if(plugin->config.g) current_output[j][k * components + 1] = (type)dst[k].g; \
468 if(plugin->config.b) current_output[j][k * components + 2] = (type)dst[k].b; \
469 if(components == 4) \
470 if(plugin->config.a) current_output[j][k * components + 3] = (type)dst[k].a; \
482 BLUR(unsigned char, 0xff, 3);
486 BLUR(unsigned char, 0xff, 4);
490 BLUR(uint16_t, 0xffff, 3);
492 case BC_RGBA16161616:
493 case BC_YUVA16161616:
494 BLUR(uint16_t, 0xffff, 4);
498 output_lock.unlock();
502 int BlurEngine::reconfigure()
504 std_dev = sqrt(-(double)(plugin->config.radius * plugin->config.radius) /
505 (2 * log (1.0 / 255.0)));
509 int BlurEngine::get_constants()
515 div = sqrt(2 * M_PI) * std_dev;
516 constants[0] = -1.783 / std_dev;
517 constants[1] = -1.723 / std_dev;
518 constants[2] = 0.6318 / std_dev;
519 constants[3] = 1.997 / std_dev;
520 constants[4] = 1.6803 / div;
521 constants[5] = 3.735 / div;
522 constants[6] = -0.6803 / div;
523 constants[7] = -0.2598 / div;
525 n_p[0] = constants[4] + constants[6];
526 n_p[1] = exp(constants[1]) *
527 (constants[7] * sin(constants[3]) -
528 (constants[6] + 2 * constants[4]) * cos(constants[3])) +
530 (constants[5] * sin(constants[2]) -
531 (2 * constants[6] + constants[4]) * cos(constants[2]));
533 n_p[2] = 2 * exp(constants[0] + constants[1]) *
534 ((constants[4] + constants[6]) * cos(constants[3]) *
535 cos(constants[2]) - constants[5] *
536 cos(constants[3]) * sin(constants[2]) -
537 constants[7] * cos(constants[2]) * sin(constants[3])) +
538 constants[6] * exp(2 * constants[0]) +
539 constants[4] * exp(2 * constants[1]);
541 n_p[3] = exp(constants[1] + 2 * constants[0]) *
542 (constants[7] * sin(constants[3]) -
543 constants[6] * cos(constants[3])) +
544 exp(constants[0] + 2 * constants[1]) *
545 (constants[5] * sin(constants[2]) - constants[4] *
550 d_p[1] = -2 * exp(constants[1]) * cos(constants[3]) -
551 2 * exp(constants[0]) * cos(constants[2]);
553 d_p[2] = 4 * cos(constants[3]) * cos(constants[2]) *
554 exp(constants[0] + constants[1]) +
555 exp(2 * constants[1]) + exp (2 * constants[0]);
557 d_p[3] = -2 * cos(constants[2]) * exp(constants[0] + 2 * constants[1]) -
558 2 * cos(constants[3]) * exp(constants[1] + 2 * constants[0]);
560 d_p[4] = exp(2 * constants[0] + 2 * constants[1]);
562 for(i = 0; i < 5; i++) d_m[i] = d_p[i];
565 for(i = 1; i <= 4; i++)
566 n_m[i] = n_p[i] - d_p[i] * n_p[0];
568 double sum_n_p, sum_n_m, sum_d;
574 for(i = 0; i < 5; i++)
581 a = sum_n_p / (1 + sum_d);
582 b = sum_n_m / (1 + sum_d);
584 for (i = 0; i < 5; i++)
586 bd_p[i] = d_p[i] * a;
587 bd_m[i] = d_m[i] * b;
592 #define BOUNDARY(x) if((x) > vmax) (x) = vmax; else if((x) < 0) (x) = 0;
594 int BlurEngine::transfer_pixels(pixel_f *src1, pixel_f *src2, pixel_f *dest, int size)
599 // printf("BlurEngine::transfer_pixels %d %d %d %d\n",
603 // plugin->config.a);
605 for(i = 0; i < size; i++)
607 sum = src1[i].r + src2[i].r;
610 sum = src1[i].g + src2[i].g;
613 sum = src1[i].b + src2[i].b;
616 sum = src1[i].a + src2[i].a;
624 int BlurEngine::multiply_alpha(pixel_f *row, int size)
627 register float alpha;
629 // for(i = 0; i < size; i++)
631 // alpha = (float)row[i].a / vmax;
632 // row[i].r *= alpha;
633 // row[i].g *= alpha;
634 // row[i].b *= alpha;
639 int BlurEngine::separate_alpha(pixel_f *row, int size)
642 register float alpha;
643 register float result;
645 // for(i = 0; i < size; i++)
647 // if(row[i].a > 0 && row[i].a < vmax)
649 // alpha = (float)row[i].a / vmax;
650 // result = (float)row[i].r / alpha;
651 // row[i].r = (result > vmax ? vmax : result);
652 // result = (float)row[i].g / alpha;
653 // row[i].g = (result > vmax ? vmax : result);
654 // result = (float)row[i].b / alpha;
655 // row[i].b = (result > vmax ? vmax : result);
661 int BlurEngine::blur_strip3(int &size)
663 multiply_alpha(src, size);
666 sp_m = src + size - 1;
668 vm = val_m + size - 1;
674 for(int k = 0; k < size; k++)
676 terms = (k < 4) ? k : 4;
677 for(l = 0; l <= terms; l++)
681 vp->r += n_p[l] * sp_p[-l].r - d_p[l] * vp[-l].r;
682 vm->r += n_m[l] * sp_m[l].r - d_m[l] * vm[l].r;
686 vp->g += n_p[l] * sp_p[-l].g - d_p[l] * vp[-l].g;
687 vm->g += n_m[l] * sp_m[l].g - d_m[l] * vm[l].g;
691 vp->b += n_p[l] * sp_p[-l].b - d_p[l] * vp[-l].b;
692 vm->b += n_m[l] * sp_m[l].b - d_m[l] * vm[l].b;
699 vp->r += (n_p[l] - bd_p[l]) * initial_p.r;
700 vm->r += (n_m[l] - bd_m[l]) * initial_m.r;
704 vp->g += (n_p[l] - bd_p[l]) * initial_p.g;
705 vm->g += (n_m[l] - bd_m[l]) * initial_m.g;
709 vp->b += (n_p[l] - bd_p[l]) * initial_p.b;
710 vm->b += (n_m[l] - bd_m[l]) * initial_m.b;
718 transfer_pixels(val_p, val_m, dst, size);
719 separate_alpha(dst, size);
724 int BlurEngine::blur_strip4(int &size)
726 multiply_alpha(src, size);
729 sp_m = src + size - 1;
731 vm = val_m + size - 1;
737 for(int k = 0; k < size; k++)
739 terms = (k < 4) ? k : 4;
741 for(l = 0; l <= terms; l++)
745 vp->r += n_p[l] * sp_p[-l].r - d_p[l] * vp[-l].r;
746 vm->r += n_m[l] * sp_m[l].r - d_m[l] * vm[l].r;
750 vp->g += n_p[l] * sp_p[-l].g - d_p[l] * vp[-l].g;
751 vm->g += n_m[l] * sp_m[l].g - d_m[l] * vm[l].g;
755 vp->b += n_p[l] * sp_p[-l].b - d_p[l] * vp[-l].b;
756 vm->b += n_m[l] * sp_m[l].b - d_m[l] * vm[l].b;
760 vp->a += n_p[l] * sp_p[-l].a - d_p[l] * vp[-l].a;
761 vm->a += n_m[l] * sp_m[l].a - d_m[l] * vm[l].a;
769 vp->r += (n_p[l] - bd_p[l]) * initial_p.r;
770 vm->r += (n_m[l] - bd_m[l]) * initial_m.r;
774 vp->g += (n_p[l] - bd_p[l]) * initial_p.g;
775 vm->g += (n_m[l] - bd_m[l]) * initial_m.g;
779 vp->b += (n_p[l] - bd_p[l]) * initial_p.b;
780 vm->b += (n_m[l] - bd_m[l]) * initial_m.b;
784 vp->a += (n_p[l] - bd_p[l]) * initial_p.a;
785 vm->a += (n_m[l] - bd_m[l]) * initial_m.a;
794 transfer_pixels(val_p, val_m, dst, size);
795 separate_alpha(dst, size);