Fixed initialisation of tf in file_open(). Without setting the memory to 0,
[cinelerra_cv/mob.git] / plugins / downsample / downsample.C
blobf2bd115cbe4a81890b601f857b0f9767f5e4ee17
1 #include <math.h>
2 #include <stdint.h>
3 #include <string.h>
5 #include "bcdisplayinfo.h"
6 #include "clip.h"
7 #include "bchash.h"
8 #include "filexml.h"
9 #include "keyframe.h"
10 #include "loadbalance.h"
11 #include "picon_png.h"
12 #include "pluginvclient.h"
13 #include "vframe.h"
15 #include <libintl.h>
16 #define _(String) gettext(String)
17 #define gettext_noop(String) String
18 #define N_(String) gettext_noop (String)
21 class DownSampleMain;
22 class DownSampleServer;
28 class DownSampleConfig
30 public:
31         DownSampleConfig();
33         int equivalent(DownSampleConfig &that);
34         void copy_from(DownSampleConfig &that);
35         void interpolate(DownSampleConfig &prev, 
36                 DownSampleConfig &next, 
37                 int64_t prev_frame, 
38                 int64_t next_frame, 
39                 int64_t current_frame);
41         int horizontal_x;
42         int vertical_y;
43         int horizontal;
44         int vertical;
45         int r;
46         int g;
47         int b;
48         int a;
52 class DownSampleToggle : public BC_CheckBox
54 public:
55         DownSampleToggle(DownSampleMain *plugin, 
56                 int x, 
57                 int y, 
58                 int *output, 
59                 char *string);
60         int handle_event();
61         DownSampleMain *plugin;
62         int *output;
65 class DownSampleSize : public BC_ISlider
67 public:
68         DownSampleSize(DownSampleMain *plugin, 
69                 int x, 
70                 int y, 
71                 int *output,
72                 int min,
73                 int max);
74         int handle_event();
75         DownSampleMain *plugin;
76         int *output;
79 class DownSampleWindow : public BC_Window
81 public:
82         DownSampleWindow(DownSampleMain *plugin, int x, int y);
83         ~DownSampleWindow();
84         
85         int create_objects();
86         int close_event();
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
100 public:
101         DownSampleMain(PluginServer *server);
102         ~DownSampleMain();
104         int process_realtime(VFrame *input_ptr, VFrame *output_ptr);
105         int is_realtime();
106         int load_defaults();
107         int save_defaults();
108         void save_data(KeyFrame *keyframe);
109         void read_data(KeyFrame *keyframe);
110         void update_gui();
112         PLUGIN_CLASS_MEMBERS(DownSampleConfig, DownSampleThread)
114         VFrame *input, *output;
115         DownSampleServer *engine;
118 class DownSamplePackage : public LoadPackage
120 public:
121         DownSamplePackage();
122         int y1, y2;
125 class DownSampleUnit : public LoadClient
127 public:
128         DownSampleUnit(DownSampleServer *server, DownSampleMain *plugin);
129         void process_package(LoadPackage *package);
130         DownSampleServer *server;
131         DownSampleMain *plugin;
134 class DownSampleServer : public LoadServer
136 public:
137         DownSampleServer(DownSampleMain *plugin, 
138                 int total_clients, 
139                 int total_packages);
140         void init_packages();
141         LoadClient* new_client();
142         LoadPackage* new_package();
143         DownSampleMain *plugin;
162 REGISTER_PLUGIN(DownSampleMain)
166 DownSampleConfig::DownSampleConfig()
168         horizontal = 2;
169         vertical = 2;
170         horizontal_x = 0;
171         vertical_y = 0;
172         r = 1;
173         g = 1;
174         b = 1;
175         a = 1;
178 int DownSampleConfig::equivalent(DownSampleConfig &that)
180         return 
181                 horizontal == that.horizontal &&
182                 vertical == that.vertical &&
183                 horizontal_x == that.horizontal_x &&
184                 vertical_y == that.vertical_y &&
185                 r == that.r &&
186                 g == that.g &&
187                 b == that.b &&
188                 a == that.a;
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;
197         r = that.r;
198         g = that.g;
199         b = that.b;
200         a = that.a;
203 void DownSampleConfig::interpolate(DownSampleConfig &prev, 
204         DownSampleConfig &next, 
205         int64_t prev_frame, 
206         int64_t next_frame, 
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);
215         r = prev.r;
216         g = prev.g;
217         b = prev.b;
218         a = prev.a;
229 PLUGIN_THREAD_OBJECT(DownSampleMain, DownSampleThread, DownSampleWindow)
233 DownSampleWindow::DownSampleWindow(DownSampleMain *plugin, int x, int y)
234  : BC_Window(plugin->gui_string, 
235         x,
236         y,
237         230, 
238         380, 
239         230, 
240         380, 
241         0, 
242         1)
244         this->plugin = plugin; 
247 DownSampleWindow::~DownSampleWindow()
251 int DownSampleWindow::create_objects()
253         int x = 10, y = 10;
255         add_subwindow(new BC_Title(x, y, _("Horizontal")));
256         y += 30;
257         add_subwindow(h = new DownSampleSize(plugin, 
258                 x, 
259                 y, 
260                 &plugin->config.horizontal,
261                 1,
262                 100));
263         y += 30;
264         add_subwindow(new BC_Title(x, y, _("Horizontal offset")));
265         y += 30;
266         add_subwindow(h_x = new DownSampleSize(plugin, 
267                 x, 
268                 y, 
269                 &plugin->config.horizontal_x,
270                 0,
271                 100));
272         y += 30;
273         add_subwindow(new BC_Title(x, y, _("Vertical")));
274         y += 30;
275         add_subwindow(v = new DownSampleSize(plugin, 
276                 x, 
277                 y, 
278                 &plugin->config.vertical,
279                 1,
280                 100));
281         y += 30;
282         add_subwindow(new BC_Title(x, y, _("Vertical offset")));
283         y += 30;
284         add_subwindow(v_y = new DownSampleSize(plugin, 
285                 x, 
286                 y, 
287                 &plugin->config.vertical_y,
288                 0,
289                 100));
290         y += 30;
291         add_subwindow(r = new DownSampleToggle(plugin, 
292                 x, 
293                 y, 
294                 &plugin->config.r, 
295                 _("Red")));
296         y += 30;
297         add_subwindow(g = new DownSampleToggle(plugin, 
298                 x, 
299                 y, 
300                 &plugin->config.g, 
301                 _("Green")));
302         y += 30;
303         add_subwindow(b = new DownSampleToggle(plugin, 
304                 x, 
305                 y, 
306                 &plugin->config.b, 
307                 _("Blue")));
308         y += 30;
309         add_subwindow(a = new DownSampleToggle(plugin, 
310                 x, 
311                 y, 
312                 &plugin->config.a, 
313                 _("Alpha")));
314         y += 30;
316         show_window();
317         flush();
318         return 0;
321 int DownSampleWindow::close_event()
323 // Set result to 1 to indicate a plugin side close
324         set_done(1);
325         return 1;
337 DownSampleToggle::DownSampleToggle(DownSampleMain *plugin, 
338         int x, 
339         int y, 
340         int *output, 
341         char *string)
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();
352         return 1;
361 DownSampleSize::DownSampleSize(DownSampleMain *plugin, 
362         int x, 
363         int y, 
364         int *output,
365         int min,
366         int max)
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();
376         return 1;
388 DownSampleMain::DownSampleMain(PluginServer *server)
389  : PluginVClient(server)
391         PLUGIN_CONSTRUCTOR_MACRO
392         engine = 0;
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])
425         {
426                 output->copy_from(input);
427         }
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();
435         return 0;
439 void DownSampleMain::update_gui()
441         if(thread)
442         {
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();
454         }
458 int DownSampleMain::load_defaults()
460         char directory[1024], string[1024];
461 // set the default directory
462         sprintf(directory, "%sdownsample.rc", BCASTDIR);
464 // load the defaults
465         defaults = new BC_Hash(directory);
466         defaults->load();
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);
476         return 0;
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);
490         defaults->save();
491         return 0;
496 void DownSampleMain::save_data(KeyFrame *keyframe)
498         FileXML output;
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);
512         output.append_tag();
513         output.terminate_string();
516 void DownSampleMain::read_data(KeyFrame *keyframe)
518         FileXML input;
520         input.set_shared_string(keyframe->data, strlen(keyframe->data));
522         int result = 0;
524         while(!result)
525         {
526                 result = input.read_tag();
528                 if(!result)
529                 {
530                         if(input.tag.title_is("DOWNSAMPLE"))
531                         {
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);
540                         }
541                 }
542         }
550 DownSamplePackage::DownSamplePackage()
551  : LoadPackage()
558 DownSampleUnit::DownSampleUnit(DownSampleServer *server, 
559         DownSampleMain *plugin)
560  : LoadClient(server)
562         this->plugin = plugin;
563         this->server = server;
566 #define SQR(x) ((x) * (x))
569 #define DOWNSAMPLE(type, temp_type, components, max) \
570 { \
571         temp_type r; \
572         temp_type g; \
573         temp_type b; \
574         temp_type a; \
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) \
582         { \
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; \
588                         j < w; \
589                         j += plugin->config.horizontal) \
590                 { \
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) \
596                         { \
598 /* Read in values */ \
599                                 r = 0; \
600                                 g = 0; \
601                                 b = 0; \
602                                 if(components == 4) a = 0; \
604                                 for(int k = y1; k < y2; k++) \
605                                 { \
606                                         type *row = rows[k] + x1 * components; \
607                                         for(int l = x1; l < x2; l++) \
608                                         { \
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++;  \
613                                         } \
614                                 } \
616 /* Write average */ \
617                                 r /= scale; \
618                                 g /= scale; \
619                                 b /= scale; \
620                                 if(components == 4) a /= scale; \
621                                 for(int k = y1; k < y2; k++) \
622                                 { \
623                                         type *row = rows[k] + x1 * components; \
624                                         for(int l = x1; l < x2; l++) \
625                                         { \
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++; \
630                                         } \
631                                 } \
632                         } \
633                 } \
634 /*printf("DOWNSAMPLE 3 %d\n", i);*/ \
635         } \
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())
646         {
647                 case BC_RGB888:
648                         DOWNSAMPLE(uint8_t, int64_t, 3, 0xff)
649                         break;
650                 case BC_RGB_FLOAT:
651                         DOWNSAMPLE(float, float, 3, 1.0)
652                         break;
653                 case BC_RGBA8888:
654                         DOWNSAMPLE(uint8_t, int64_t, 4, 0xff)
655                         break;
656                 case BC_RGBA_FLOAT:
657                         DOWNSAMPLE(float, float, 4, 1.0)
658                         break;
659                 case BC_RGB161616:
660                         DOWNSAMPLE(uint16_t, int64_t, 3, 0xffff)
661                         break;
662                 case BC_RGBA16161616:
663                         DOWNSAMPLE(uint16_t, int64_t, 4, 0xffff)
664                         break;
665                 case BC_YUV888:
666                         DOWNSAMPLE(uint8_t, int64_t, 3, 0xff)
667                         break;
668                 case BC_YUVA8888:
669                         DOWNSAMPLE(uint8_t, int64_t, 4, 0xff)
670                         break;
671                 case BC_YUV161616:
672                         DOWNSAMPLE(uint16_t, int64_t, 3, 0xffff)
673                         break;
674                 case BC_YUVA16161616:
675                         DOWNSAMPLE(uint16_t, int64_t, 4, 0xffff)
676                         break;
677         }
685 DownSampleServer::DownSampleServer(DownSampleMain *plugin, 
686         int total_clients, 
687         int total_packages)
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++)
700         {
701                 DownSamplePackage *package = (DownSamplePackage*)get_package(i);
702                 package->y1 = y1;
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);
706                 y1 = package->y2;
707         }
710 LoadClient* DownSampleServer::new_client()
712         return new DownSampleUnit(this, plugin);
715 LoadPackage* DownSampleServer::new_package()
717         return new DownSamplePackage;