5 #include "bcdisplayinfo.h"
10 #include "loadbalance.h"
11 #include "picon_png.h"
12 #include "pluginvclient.h"
16 #define _(String) gettext(String)
17 #define gettext_noop(String) String
18 #define N_(String) gettext_noop (String)
22 class DownSampleServer;
28 class DownSampleConfig
33 int equivalent(DownSampleConfig &that);
34 void copy_from(DownSampleConfig &that);
35 void interpolate(DownSampleConfig &prev,
36 DownSampleConfig &next,
39 int64_t current_frame);
52 class DownSampleToggle : public BC_CheckBox
55 DownSampleToggle(DownSampleMain *plugin,
61 DownSampleMain *plugin;
65 class DownSampleSize : public BC_ISlider
68 DownSampleSize(DownSampleMain *plugin,
75 DownSampleMain *plugin;
79 class DownSampleWindow : public BC_Window
82 DownSampleWindow(DownSampleMain *plugin, int x, int y);
88 DownSampleToggle *r, *g, *b, *a;
89 DownSampleSize *h, *v, *h_x, *v_y;
90 DownSampleMain *plugin;
95 PLUGIN_THREAD_HEADER(DownSampleMain, DownSampleThread, DownSampleWindow)
98 class DownSampleMain : public PluginVClient
101 DownSampleMain(PluginServer *server);
104 int process_realtime(VFrame *input_ptr, VFrame *output_ptr);
108 void save_data(KeyFrame *keyframe);
109 void read_data(KeyFrame *keyframe);
112 PLUGIN_CLASS_MEMBERS(DownSampleConfig, DownSampleThread)
114 VFrame *input, *output;
115 DownSampleServer *engine;
118 class DownSamplePackage : public LoadPackage
125 class DownSampleUnit : public LoadClient
128 DownSampleUnit(DownSampleServer *server, DownSampleMain *plugin);
129 void process_package(LoadPackage *package);
130 DownSampleServer *server;
131 DownSampleMain *plugin;
134 class DownSampleServer : public LoadServer
137 DownSampleServer(DownSampleMain *plugin,
140 void init_packages();
141 LoadClient* new_client();
142 LoadPackage* new_package();
143 DownSampleMain *plugin;
162 REGISTER_PLUGIN(DownSampleMain)
166 DownSampleConfig::DownSampleConfig()
178 int DownSampleConfig::equivalent(DownSampleConfig &that)
181 horizontal == that.horizontal &&
182 vertical == that.vertical &&
183 horizontal_x == that.horizontal_x &&
184 vertical_y == that.vertical_y &&
191 void DownSampleConfig::copy_from(DownSampleConfig &that)
193 horizontal = that.horizontal;
194 vertical = that.vertical;
195 horizontal_x = that.horizontal_x;
196 vertical_y = that.vertical_y;
203 void DownSampleConfig::interpolate(DownSampleConfig &prev,
204 DownSampleConfig &next,
207 int64_t current_frame)
209 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
210 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
211 this->horizontal = (int)(prev.horizontal * prev_scale + next.horizontal * next_scale);
212 this->vertical = (int)(prev.vertical * prev_scale + next.vertical * next_scale);
213 this->horizontal_x = (int)(prev.horizontal_x * prev_scale + next.horizontal_x * next_scale);
214 this->vertical_y = (int)(prev.vertical_y * prev_scale + next.vertical_y * next_scale);
229 PLUGIN_THREAD_OBJECT(DownSampleMain, DownSampleThread, DownSampleWindow)
233 DownSampleWindow::DownSampleWindow(DownSampleMain *plugin, int x, int y)
234 : BC_Window(plugin->gui_string,
244 this->plugin = plugin;
247 DownSampleWindow::~DownSampleWindow()
251 int DownSampleWindow::create_objects()
255 add_subwindow(new BC_Title(x, y, _("Horizontal")));
257 add_subwindow(h = new DownSampleSize(plugin,
260 &plugin->config.horizontal,
264 add_subwindow(new BC_Title(x, y, _("Horizontal offset")));
266 add_subwindow(h_x = new DownSampleSize(plugin,
269 &plugin->config.horizontal_x,
273 add_subwindow(new BC_Title(x, y, _("Vertical")));
275 add_subwindow(v = new DownSampleSize(plugin,
278 &plugin->config.vertical,
282 add_subwindow(new BC_Title(x, y, _("Vertical offset")));
284 add_subwindow(v_y = new DownSampleSize(plugin,
287 &plugin->config.vertical_y,
291 add_subwindow(r = new DownSampleToggle(plugin,
297 add_subwindow(g = new DownSampleToggle(plugin,
303 add_subwindow(b = new DownSampleToggle(plugin,
309 add_subwindow(a = new DownSampleToggle(plugin,
321 int DownSampleWindow::close_event()
323 // Set result to 1 to indicate a plugin side close
337 DownSampleToggle::DownSampleToggle(DownSampleMain *plugin,
342 : BC_CheckBox(x, y, *output, string)
344 this->plugin = plugin;
345 this->output = output;
348 int DownSampleToggle::handle_event()
350 *output = get_value();
351 plugin->send_configure_change();
361 DownSampleSize::DownSampleSize(DownSampleMain *plugin,
367 : BC_ISlider(x, y, 0, 200, 200, min, max, *output)
369 this->plugin = plugin;
370 this->output = output;
372 int DownSampleSize::handle_event()
374 *output = get_value();
375 plugin->send_configure_change();
388 DownSampleMain::DownSampleMain(PluginServer *server)
389 : PluginVClient(server)
391 PLUGIN_CONSTRUCTOR_MACRO
395 DownSampleMain::~DownSampleMain()
397 PLUGIN_DESTRUCTOR_MACRO
399 if(engine) delete engine;
402 char* DownSampleMain::plugin_title() { return N_("Downsample"); }
403 int DownSampleMain::is_realtime() { return 1; }
406 NEW_PICON_MACRO(DownSampleMain)
408 SHOW_GUI_MACRO(DownSampleMain, DownSampleThread)
410 SET_STRING_MACRO(DownSampleMain)
412 RAISE_WINDOW_MACRO(DownSampleMain)
414 LOAD_CONFIGURATION_MACRO(DownSampleMain, DownSampleConfig)
417 int DownSampleMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
419 this->input = input_ptr;
420 this->output = output_ptr;
421 load_configuration();
423 // Copy to destination
424 if(output->get_rows()[0] != input->get_rows()[0])
426 output->copy_from(input);
429 // Process in destination
430 if(!engine) engine = new DownSampleServer(this,
431 get_project_smp() + 1,
432 get_project_smp() + 1);
433 engine->process_packages();
439 void DownSampleMain::update_gui()
443 load_configuration();
444 thread->window->lock_window();
445 thread->window->h->update(config.horizontal);
446 thread->window->v->update(config.vertical);
447 thread->window->h_x->update(config.horizontal_x);
448 thread->window->v_y->update(config.vertical_y);
449 thread->window->r->update(config.r);
450 thread->window->g->update(config.g);
451 thread->window->b->update(config.b);
452 thread->window->a->update(config.a);
453 thread->window->unlock_window();
458 int DownSampleMain::load_defaults()
460 char directory[1024], string[1024];
461 // set the default directory
462 sprintf(directory, "%sdownsample.rc", BCASTDIR);
465 defaults = new BC_Hash(directory);
468 config.horizontal = defaults->get("HORIZONTAL", config.horizontal);
469 config.vertical = defaults->get("VERTICAL", config.vertical);
470 config.horizontal_x = defaults->get("HORIZONTAL_X", config.horizontal_x);
471 config.vertical_y = defaults->get("VERTICAL_Y", config.vertical_y);
472 config.r = defaults->get("R", config.r);
473 config.g = defaults->get("G", config.g);
474 config.b = defaults->get("B", config.b);
475 config.a = defaults->get("A", config.a);
480 int DownSampleMain::save_defaults()
482 defaults->update("HORIZONTAL", config.horizontal);
483 defaults->update("VERTICAL", config.vertical);
484 defaults->update("HORIZONTAL_X", config.horizontal_x);
485 defaults->update("VERTICAL_Y", config.vertical_y);
486 defaults->update("R", config.r);
487 defaults->update("G", config.g);
488 defaults->update("B", config.b);
489 defaults->update("A", config.a);
496 void DownSampleMain::save_data(KeyFrame *keyframe)
500 // cause data to be stored directly in text
501 output.set_shared_string(keyframe->data, MESSAGESIZE);
502 output.tag.set_title("DOWNSAMPLE");
504 output.tag.set_property("HORIZONTAL", config.horizontal);
505 output.tag.set_property("VERTICAL", config.vertical);
506 output.tag.set_property("HORIZONTAL_X", config.horizontal_x);
507 output.tag.set_property("VERTICAL_Y", config.vertical_y);
508 output.tag.set_property("R", config.r);
509 output.tag.set_property("G", config.g);
510 output.tag.set_property("B", config.b);
511 output.tag.set_property("A", config.a);
513 output.terminate_string();
516 void DownSampleMain::read_data(KeyFrame *keyframe)
520 input.set_shared_string(keyframe->data, strlen(keyframe->data));
526 result = input.read_tag();
530 if(input.tag.title_is("DOWNSAMPLE"))
532 config.horizontal = input.tag.get_property("HORIZONTAL", config.horizontal);
533 config.vertical = input.tag.get_property("VERTICAL", config.vertical);
534 config.horizontal_x = input.tag.get_property("HORIZONTAL_X", config.horizontal_x);
535 config.vertical_y = input.tag.get_property("VERTICAL_Y", config.vertical_y);
536 config.r = input.tag.get_property("R", config.r);
537 config.g = input.tag.get_property("G", config.g);
538 config.b = input.tag.get_property("B", config.b);
539 config.a = input.tag.get_property("A", config.a);
550 DownSamplePackage::DownSamplePackage()
558 DownSampleUnit::DownSampleUnit(DownSampleServer *server,
559 DownSampleMain *plugin)
562 this->plugin = plugin;
563 this->server = server;
566 #define SQR(x) ((x) * (x))
569 #define DOWNSAMPLE(type, temp_type, components, max) \
575 int do_r = plugin->config.r; \
576 int do_g = plugin->config.g; \
577 int do_b = plugin->config.b; \
578 int do_a = plugin->config.a; \
579 type **rows = (type**)plugin->output->get_rows(); \
581 for(int i = pkg->y1; i < pkg->y2; i += plugin->config.vertical) \
583 int y1 = MAX(i, 0); \
584 int y2 = MIN(i + plugin->config.vertical, h); \
587 for(int j = plugin->config.horizontal_x - plugin->config.horizontal; \
589 j += plugin->config.horizontal) \
591 int x1 = MAX(j, 0); \
592 int x2 = MIN(j + plugin->config.horizontal, w); \
594 temp_type scale = (x2 - x1) * (y2 - y1); \
595 if(x2 > x1 && y2 > y1) \
598 /* Read in values */ \
602 if(components == 4) a = 0; \
604 for(int k = y1; k < y2; k++) \
606 type *row = rows[k] + x1 * components; \
607 for(int l = x1; l < x2; l++) \
609 if(do_r) r += *row++; else row++; \
610 if(do_g) g += *row++; else row++; \
611 if(do_b) b += *row++; else row++; \
612 if(components == 4) if(do_a) a += *row++; else row++; \
616 /* Write average */ \
620 if(components == 4) a /= scale; \
621 for(int k = y1; k < y2; k++) \
623 type *row = rows[k] + x1 * components; \
624 for(int l = x1; l < x2; l++) \
626 if(do_r) *row++ = r; else row++; \
627 if(do_g) *row++ = g; else row++; \
628 if(do_b) *row++ = b; else row++; \
629 if(components == 4) if(do_a) *row++ = a; else row++; \
634 /*printf("DOWNSAMPLE 3 %d\n", i);*/ \
638 void DownSampleUnit::process_package(LoadPackage *package)
640 DownSamplePackage *pkg = (DownSamplePackage*)package;
641 int h = plugin->output->get_h();
642 int w = plugin->output->get_w();
645 switch(plugin->input->get_color_model())
648 DOWNSAMPLE(uint8_t, int64_t, 3, 0xff)
651 DOWNSAMPLE(float, float, 3, 1.0)
654 DOWNSAMPLE(uint8_t, int64_t, 4, 0xff)
657 DOWNSAMPLE(float, float, 4, 1.0)
660 DOWNSAMPLE(uint16_t, int64_t, 3, 0xffff)
662 case BC_RGBA16161616:
663 DOWNSAMPLE(uint16_t, int64_t, 4, 0xffff)
666 DOWNSAMPLE(uint8_t, int64_t, 3, 0xff)
669 DOWNSAMPLE(uint8_t, int64_t, 4, 0xff)
672 DOWNSAMPLE(uint16_t, int64_t, 3, 0xffff)
674 case BC_YUVA16161616:
675 DOWNSAMPLE(uint16_t, int64_t, 4, 0xffff)
685 DownSampleServer::DownSampleServer(DownSampleMain *plugin,
688 : LoadServer(total_clients, total_packages)
690 this->plugin = plugin;
693 void DownSampleServer::init_packages()
695 int y1 = plugin->config.vertical_y - plugin->config.vertical;
696 int total_strips = (int)((float)plugin->output->get_h() / plugin->config.vertical + 1);
697 int strips_per_package = (int)((float)total_strips / get_total_packages() + 1);
699 for(int i = 0; i < get_total_packages(); i++)
701 DownSamplePackage *package = (DownSamplePackage*)get_package(i);
703 package->y2 = y1 + strips_per_package * plugin->config.vertical;
704 package->y1 = MIN(plugin->output->get_h(), package->y1);
705 package->y2 = MIN(plugin->output->get_h(), package->y2);
710 LoadClient* DownSampleServer::new_client()
712 return new DownSampleUnit(this, plugin);
715 LoadPackage* DownSampleServer::new_package()
717 return new DownSamplePackage;