00001 #include <math.h>
00002 #include <stdint.h>
00003 #include <string.h>
00004
00005 #include "bcdisplayinfo.h"
00006 #include "clip.h"
00007 #include "bchash.h"
00008 #include "filexml.h"
00009 #include "keyframe.h"
00010 #include "loadbalance.h"
00011 #include "picon_png.h"
00012 #include "pluginvclient.h"
00013 #include "vframe.h"
00014
00015 #include <libintl.h>
00016 #define _(String) gettext(String)
00017 #define gettext_noop(String) String
00018 #define N_(String) gettext_noop (String)
00019
00020
00021 class DownSampleMain;
00022 class DownSampleServer;
00023
00024
00025
00026
00027
00028 class DownSampleConfig
00029 {
00030 public:
00031 DownSampleConfig();
00032
00033 int equivalent(DownSampleConfig &that);
00034 void copy_from(DownSampleConfig &that);
00035 void interpolate(DownSampleConfig &prev,
00036 DownSampleConfig &next,
00037 int64_t prev_frame,
00038 int64_t next_frame,
00039 int64_t current_frame);
00040
00041 int horizontal_x;
00042 int vertical_y;
00043 int horizontal;
00044 int vertical;
00045 int r;
00046 int g;
00047 int b;
00048 int a;
00049 };
00050
00051
00052 class DownSampleToggle : public BC_CheckBox
00053 {
00054 public:
00055 DownSampleToggle(DownSampleMain *plugin,
00056 int x,
00057 int y,
00058 int *output,
00059 char *string);
00060 int handle_event();
00061 DownSampleMain *plugin;
00062 int *output;
00063 };
00064
00065 class DownSampleSize : public BC_ISlider
00066 {
00067 public:
00068 DownSampleSize(DownSampleMain *plugin,
00069 int x,
00070 int y,
00071 int *output,
00072 int min,
00073 int max);
00074 int handle_event();
00075 DownSampleMain *plugin;
00076 int *output;
00077 };
00078
00079 class DownSampleWindow : public BC_Window
00080 {
00081 public:
00082 DownSampleWindow(DownSampleMain *plugin, int x, int y);
00083 ~DownSampleWindow();
00084
00085 int create_objects();
00086 int close_event();
00087
00088 DownSampleToggle *r, *g, *b, *a;
00089 DownSampleSize *h, *v, *h_x, *v_y;
00090 DownSampleMain *plugin;
00091 };
00092
00093
00094
00095 PLUGIN_THREAD_HEADER(DownSampleMain, DownSampleThread, DownSampleWindow)
00096
00097
00098 class DownSampleMain : public PluginVClient
00099 {
00100 public:
00101 DownSampleMain(PluginServer *server);
00102 ~DownSampleMain();
00103
00104 int process_realtime(VFrame *input_ptr, VFrame *output_ptr);
00105 int is_realtime();
00106 int load_defaults();
00107 int save_defaults();
00108 void save_data(KeyFrame *keyframe);
00109 void read_data(KeyFrame *keyframe);
00110 void update_gui();
00111
00112 PLUGIN_CLASS_MEMBERS(DownSampleConfig, DownSampleThread)
00113
00114 VFrame *input, *output;
00115 DownSampleServer *engine;
00116 };
00117
00118 class DownSamplePackage : public LoadPackage
00119 {
00120 public:
00121 DownSamplePackage();
00122 int y1, y2;
00123 };
00124
00125 class DownSampleUnit : public LoadClient
00126 {
00127 public:
00128 DownSampleUnit(DownSampleServer *server, DownSampleMain *plugin);
00129 void process_package(LoadPackage *package);
00130 DownSampleServer *server;
00131 DownSampleMain *plugin;
00132 };
00133
00134 class DownSampleServer : public LoadServer
00135 {
00136 public:
00137 DownSampleServer(DownSampleMain *plugin,
00138 int total_clients,
00139 int total_packages);
00140 void init_packages();
00141 LoadClient* new_client();
00142 LoadPackage* new_package();
00143 DownSampleMain *plugin;
00144 };
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162 REGISTER_PLUGIN(DownSampleMain)
00163
00164
00165
00166 DownSampleConfig::DownSampleConfig()
00167 {
00168 horizontal = 2;
00169 vertical = 2;
00170 horizontal_x = 0;
00171 vertical_y = 0;
00172 r = 1;
00173 g = 1;
00174 b = 1;
00175 a = 1;
00176 }
00177
00178 int DownSampleConfig::equivalent(DownSampleConfig &that)
00179 {
00180 return
00181 horizontal == that.horizontal &&
00182 vertical == that.vertical &&
00183 horizontal_x == that.horizontal_x &&
00184 vertical_y == that.vertical_y &&
00185 r == that.r &&
00186 g == that.g &&
00187 b == that.b &&
00188 a == that.a;
00189 }
00190
00191 void DownSampleConfig::copy_from(DownSampleConfig &that)
00192 {
00193 horizontal = that.horizontal;
00194 vertical = that.vertical;
00195 horizontal_x = that.horizontal_x;
00196 vertical_y = that.vertical_y;
00197 r = that.r;
00198 g = that.g;
00199 b = that.b;
00200 a = that.a;
00201 }
00202
00203 void DownSampleConfig::interpolate(DownSampleConfig &prev,
00204 DownSampleConfig &next,
00205 int64_t prev_frame,
00206 int64_t next_frame,
00207 int64_t current_frame)
00208 {
00209 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
00210 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
00211 this->horizontal = (int)(prev.horizontal * prev_scale + next.horizontal * next_scale);
00212 this->vertical = (int)(prev.vertical * prev_scale + next.vertical * next_scale);
00213 this->horizontal_x = (int)(prev.horizontal_x * prev_scale + next.horizontal_x * next_scale);
00214 this->vertical_y = (int)(prev.vertical_y * prev_scale + next.vertical_y * next_scale);
00215 r = prev.r;
00216 g = prev.g;
00217 b = prev.b;
00218 a = prev.a;
00219 }
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229 PLUGIN_THREAD_OBJECT(DownSampleMain, DownSampleThread, DownSampleWindow)
00230
00231
00232
00233 DownSampleWindow::DownSampleWindow(DownSampleMain *plugin, int x, int y)
00234 : BC_Window(plugin->gui_string,
00235 x,
00236 y,
00237 230,
00238 380,
00239 230,
00240 380,
00241 0,
00242 1)
00243 {
00244 this->plugin = plugin;
00245 }
00246
00247 DownSampleWindow::~DownSampleWindow()
00248 {
00249 }
00250
00251 int DownSampleWindow::create_objects()
00252 {
00253 int x = 10, y = 10;
00254
00255 add_subwindow(new BC_Title(x, y, _("Horizontal")));
00256 y += 30;
00257 add_subwindow(h = new DownSampleSize(plugin,
00258 x,
00259 y,
00260 &plugin->config.horizontal,
00261 1,
00262 100));
00263 y += 30;
00264 add_subwindow(new BC_Title(x, y, _("Horizontal offset")));
00265 y += 30;
00266 add_subwindow(h_x = new DownSampleSize(plugin,
00267 x,
00268 y,
00269 &plugin->config.horizontal_x,
00270 0,
00271 100));
00272 y += 30;
00273 add_subwindow(new BC_Title(x, y, _("Vertical")));
00274 y += 30;
00275 add_subwindow(v = new DownSampleSize(plugin,
00276 x,
00277 y,
00278 &plugin->config.vertical,
00279 1,
00280 100));
00281 y += 30;
00282 add_subwindow(new BC_Title(x, y, _("Vertical offset")));
00283 y += 30;
00284 add_subwindow(v_y = new DownSampleSize(plugin,
00285 x,
00286 y,
00287 &plugin->config.vertical_y,
00288 0,
00289 100));
00290 y += 30;
00291 add_subwindow(r = new DownSampleToggle(plugin,
00292 x,
00293 y,
00294 &plugin->config.r,
00295 _("Red")));
00296 y += 30;
00297 add_subwindow(g = new DownSampleToggle(plugin,
00298 x,
00299 y,
00300 &plugin->config.g,
00301 _("Green")));
00302 y += 30;
00303 add_subwindow(b = new DownSampleToggle(plugin,
00304 x,
00305 y,
00306 &plugin->config.b,
00307 _("Blue")));
00308 y += 30;
00309 add_subwindow(a = new DownSampleToggle(plugin,
00310 x,
00311 y,
00312 &plugin->config.a,
00313 _("Alpha")));
00314 y += 30;
00315
00316 show_window();
00317 flush();
00318 return 0;
00319 }
00320
00321 int DownSampleWindow::close_event()
00322 {
00323
00324 set_done(1);
00325 return 1;
00326 }
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337 DownSampleToggle::DownSampleToggle(DownSampleMain *plugin,
00338 int x,
00339 int y,
00340 int *output,
00341 char *string)
00342 : BC_CheckBox(x, y, *output, string)
00343 {
00344 this->plugin = plugin;
00345 this->output = output;
00346 }
00347
00348 int DownSampleToggle::handle_event()
00349 {
00350 *output = get_value();
00351 plugin->send_configure_change();
00352 return 1;
00353 }
00354
00355
00356
00357
00358
00359
00360
00361 DownSampleSize::DownSampleSize(DownSampleMain *plugin,
00362 int x,
00363 int y,
00364 int *output,
00365 int min,
00366 int max)
00367 : BC_ISlider(x, y, 0, 200, 200, min, max, *output)
00368 {
00369 this->plugin = plugin;
00370 this->output = output;
00371 }
00372 int DownSampleSize::handle_event()
00373 {
00374 *output = get_value();
00375 plugin->send_configure_change();
00376 return 1;
00377 }
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388 DownSampleMain::DownSampleMain(PluginServer *server)
00389 : PluginVClient(server)
00390 {
00391 PLUGIN_CONSTRUCTOR_MACRO
00392 engine = 0;
00393 }
00394
00395 DownSampleMain::~DownSampleMain()
00396 {
00397 PLUGIN_DESTRUCTOR_MACRO
00398
00399 if(engine) delete engine;
00400 }
00401
00402 char* DownSampleMain::plugin_title() { return N_("Downsample"); }
00403 int DownSampleMain::is_realtime() { return 1; }
00404
00405
00406 NEW_PICON_MACRO(DownSampleMain)
00407
00408 SHOW_GUI_MACRO(DownSampleMain, DownSampleThread)
00409
00410 SET_STRING_MACRO(DownSampleMain)
00411
00412 RAISE_WINDOW_MACRO(DownSampleMain)
00413
00414 LOAD_CONFIGURATION_MACRO(DownSampleMain, DownSampleConfig)
00415
00416
00417 int DownSampleMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
00418 {
00419 this->input = input_ptr;
00420 this->output = output_ptr;
00421 load_configuration();
00422
00423
00424 if(output->get_rows()[0] != input->get_rows()[0])
00425 {
00426 output->copy_from(input);
00427 }
00428
00429
00430 if(!engine) engine = new DownSampleServer(this,
00431 get_project_smp() + 1,
00432 get_project_smp() + 1);
00433 engine->process_packages();
00434
00435 return 0;
00436 }
00437
00438
00439 void DownSampleMain::update_gui()
00440 {
00441 if(thread)
00442 {
00443 load_configuration();
00444 thread->window->lock_window();
00445 thread->window->h->update(config.horizontal);
00446 thread->window->v->update(config.vertical);
00447 thread->window->h_x->update(config.horizontal_x);
00448 thread->window->v_y->update(config.vertical_y);
00449 thread->window->r->update(config.r);
00450 thread->window->g->update(config.g);
00451 thread->window->b->update(config.b);
00452 thread->window->a->update(config.a);
00453 thread->window->unlock_window();
00454 }
00455 }
00456
00457
00458 int DownSampleMain::load_defaults()
00459 {
00460 char directory[1024], string[1024];
00461
00462 sprintf(directory, "%sdownsample.rc", BCASTDIR);
00463
00464
00465 defaults = new BC_Hash(directory);
00466 defaults->load();
00467
00468 config.horizontal = defaults->get("HORIZONTAL", config.horizontal);
00469 config.vertical = defaults->get("VERTICAL", config.vertical);
00470 config.horizontal_x = defaults->get("HORIZONTAL_X", config.horizontal_x);
00471 config.vertical_y = defaults->get("VERTICAL_Y", config.vertical_y);
00472 config.r = defaults->get("R", config.r);
00473 config.g = defaults->get("G", config.g);
00474 config.b = defaults->get("B", config.b);
00475 config.a = defaults->get("A", config.a);
00476 return 0;
00477 }
00478
00479
00480 int DownSampleMain::save_defaults()
00481 {
00482 defaults->update("HORIZONTAL", config.horizontal);
00483 defaults->update("VERTICAL", config.vertical);
00484 defaults->update("HORIZONTAL_X", config.horizontal_x);
00485 defaults->update("VERTICAL_Y", config.vertical_y);
00486 defaults->update("R", config.r);
00487 defaults->update("G", config.g);
00488 defaults->update("B", config.b);
00489 defaults->update("A", config.a);
00490 defaults->save();
00491 return 0;
00492 }
00493
00494
00495
00496 void DownSampleMain::save_data(KeyFrame *keyframe)
00497 {
00498 FileXML output;
00499
00500
00501 output.set_shared_string(keyframe->data, MESSAGESIZE);
00502 output.tag.set_title("DOWNSAMPLE");
00503
00504 output.tag.set_property("HORIZONTAL", config.horizontal);
00505 output.tag.set_property("VERTICAL", config.vertical);
00506 output.tag.set_property("HORIZONTAL_X", config.horizontal_x);
00507 output.tag.set_property("VERTICAL_Y", config.vertical_y);
00508 output.tag.set_property("R", config.r);
00509 output.tag.set_property("G", config.g);
00510 output.tag.set_property("B", config.b);
00511 output.tag.set_property("A", config.a);
00512 output.append_tag();
00513 output.tag.set_title("/DOWNSAMPLE");
00514 output.append_tag();
00515 output.terminate_string();
00516 }
00517
00518 void DownSampleMain::read_data(KeyFrame *keyframe)
00519 {
00520 FileXML input;
00521
00522 input.set_shared_string(keyframe->data, strlen(keyframe->data));
00523
00524 int result = 0;
00525
00526 while(!result)
00527 {
00528 result = input.read_tag();
00529
00530 if(!result)
00531 {
00532 if(input.tag.title_is("DOWNSAMPLE"))
00533 {
00534 config.horizontal = input.tag.get_property("HORIZONTAL", config.horizontal);
00535 config.vertical = input.tag.get_property("VERTICAL", config.vertical);
00536 config.horizontal_x = input.tag.get_property("HORIZONTAL_X", config.horizontal_x);
00537 config.vertical_y = input.tag.get_property("VERTICAL_Y", config.vertical_y);
00538 config.r = input.tag.get_property("R", config.r);
00539 config.g = input.tag.get_property("G", config.g);
00540 config.b = input.tag.get_property("B", config.b);
00541 config.a = input.tag.get_property("A", config.a);
00542 }
00543 }
00544 }
00545 }
00546
00547
00548
00549
00550
00551
00552 DownSamplePackage::DownSamplePackage()
00553 : LoadPackage()
00554 {
00555 }
00556
00557
00558
00559
00560 DownSampleUnit::DownSampleUnit(DownSampleServer *server,
00561 DownSampleMain *plugin)
00562 : LoadClient(server)
00563 {
00564 this->plugin = plugin;
00565 this->server = server;
00566 }
00567
00568 #define SQR(x) ((x) * (x))
00569
00570
00571 #define DOWNSAMPLE(type, temp_type, components, max) \
00572 { \
00573 temp_type r; \
00574 temp_type g; \
00575 temp_type b; \
00576 temp_type a; \
00577 int do_r = plugin->config.r; \
00578 int do_g = plugin->config.g; \
00579 int do_b = plugin->config.b; \
00580 int do_a = plugin->config.a; \
00581 type **rows = (type**)plugin->output->get_rows(); \
00582 \
00583 for(int i = pkg->y1; i < pkg->y2; i += plugin->config.vertical) \
00584 { \
00585 int y1 = MAX(i, 0); \
00586 int y2 = MIN(i + plugin->config.vertical, h); \
00587 \
00588 \
00589 for(int j = plugin->config.horizontal_x - plugin->config.horizontal; \
00590 j < w; \
00591 j += plugin->config.horizontal) \
00592 { \
00593 int x1 = MAX(j, 0); \
00594 int x2 = MIN(j + plugin->config.horizontal, w); \
00595 \
00596 temp_type scale = (x2 - x1) * (y2 - y1); \
00597 if(x2 > x1 && y2 > y1) \
00598 { \
00599 \
00600 \
00601 r = 0; \
00602 g = 0; \
00603 b = 0; \
00604 if(components == 4) a = 0; \
00605 \
00606 for(int k = y1; k < y2; k++) \
00607 { \
00608 type *row = rows[k] + x1 * components; \
00609 for(int l = x1; l < x2; l++) \
00610 { \
00611 if(do_r) r += *row++; else row++; \
00612 if(do_g) g += *row++; else row++; \
00613 if(do_b) b += *row++; else row++; \
00614 if(components == 4) if(do_a) a += *row++; else row++; \
00615 } \
00616 } \
00617 \
00618 \
00619 r /= scale; \
00620 g /= scale; \
00621 b /= scale; \
00622 if(components == 4) a /= scale; \
00623 for(int k = y1; k < y2; k++) \
00624 { \
00625 type *row = rows[k] + x1 * components; \
00626 for(int l = x1; l < x2; l++) \
00627 { \
00628 if(do_r) *row++ = r; else row++; \
00629 if(do_g) *row++ = g; else row++; \
00630 if(do_b) *row++ = b; else row++; \
00631 if(components == 4) if(do_a) *row++ = a; else row++; \
00632 } \
00633 } \
00634 } \
00635 } \
00636 \
00637 } \
00638 }
00639
00640 void DownSampleUnit::process_package(LoadPackage *package)
00641 {
00642 DownSamplePackage *pkg = (DownSamplePackage*)package;
00643 int h = plugin->output->get_h();
00644 int w = plugin->output->get_w();
00645
00646
00647 switch(plugin->input->get_color_model())
00648 {
00649 case BC_RGB888:
00650 DOWNSAMPLE(uint8_t, int64_t, 3, 0xff)
00651 break;
00652 case BC_RGB_FLOAT:
00653 DOWNSAMPLE(float, float, 3, 1.0)
00654 break;
00655 case BC_RGBA8888:
00656 DOWNSAMPLE(uint8_t, int64_t, 4, 0xff)
00657 break;
00658 case BC_RGBA_FLOAT:
00659 DOWNSAMPLE(float, float, 4, 1.0)
00660 break;
00661 case BC_RGB161616:
00662 DOWNSAMPLE(uint16_t, int64_t, 3, 0xffff)
00663 break;
00664 case BC_RGBA16161616:
00665 DOWNSAMPLE(uint16_t, int64_t, 4, 0xffff)
00666 break;
00667 case BC_YUV888:
00668 DOWNSAMPLE(uint8_t, int64_t, 3, 0xff)
00669 break;
00670 case BC_YUVA8888:
00671 DOWNSAMPLE(uint8_t, int64_t, 4, 0xff)
00672 break;
00673 case BC_YUV161616:
00674 DOWNSAMPLE(uint16_t, int64_t, 3, 0xffff)
00675 break;
00676 case BC_YUVA16161616:
00677 DOWNSAMPLE(uint16_t, int64_t, 4, 0xffff)
00678 break;
00679 }
00680 }
00681
00682
00683
00684
00685
00686
00687 DownSampleServer::DownSampleServer(DownSampleMain *plugin,
00688 int total_clients,
00689 int total_packages)
00690 : LoadServer(total_clients, total_packages)
00691 {
00692 this->plugin = plugin;
00693 }
00694
00695 void DownSampleServer::init_packages()
00696 {
00697 int y1 = plugin->config.vertical_y - plugin->config.vertical;
00698 int total_strips = (int)((float)plugin->output->get_h() / plugin->config.vertical + 1);
00699 int strips_per_package = (int)((float)total_strips / get_total_packages() + 1);
00700
00701 for(int i = 0; i < get_total_packages(); i++)
00702 {
00703 DownSamplePackage *package = (DownSamplePackage*)get_package(i);
00704 package->y1 = y1;
00705 package->y2 = y1 + strips_per_package * plugin->config.vertical;
00706 package->y1 = MIN(plugin->output->get_h(), package->y1);
00707 package->y2 = MIN(plugin->output->get_h(), package->y2);
00708 y1 = package->y2;
00709 }
00710 }
00711
00712 LoadClient* DownSampleServer::new_client()
00713 {
00714 return new DownSampleUnit(this, plugin);
00715 }
00716
00717 LoadPackage* DownSampleServer::new_package()
00718 {
00719 return new DownSamplePackage;
00720 }
00721
00722
00723
00724
00725