r200: Merged the official release 1.1.9.
[cinelerra_cv.git] / plugins / histogram / histogram.C
blobd274e148bc39df9c7013bb64cc925917020b391b
1 #include <math.h>
2 #include <stdint.h>
3 #include <string.h>
4 #include <unistd.h>
6 #include "bcdisplayinfo.h"
7 #include "bcsignals.h"
8 #include "clip.h"
9 #include "defaults.h"
10 #include "filexml.h"
11 #include "keyframe.h"
12 #include "language.h"
13 #include "loadbalance.h"
14 #include "max_picon_png.h"
15 #include "mid_picon_png.h"
16 #include "min_picon_png.h"
17 #include "picon_png.h"
18 #include "plugincolors.h"
19 #include "pluginvclient.h"
20 #include "vframe.h"
24 class HistogramMain;
25 class HistogramEngine;
26 class HistogramWindow;
28 // modes
29 #define HISTOGRAM_RED 0
30 #define HISTOGRAM_GREEN 1
31 #define HISTOGRAM_BLUE 2
32 #define HISTOGRAM_ALPHA 3
33 #define HISTOGRAM_VALUE 4
35 // range
36 #define HISTOGRAM_RANGE 0x10000
38 #define THRESHOLD_SCALE 1000
40 class HistogramConfig
42 public:
43         HistogramConfig();
45         int equivalent(HistogramConfig &that);
46         void copy_from(HistogramConfig &that);
47         void interpolate(HistogramConfig &prev, 
48                 HistogramConfig &next, 
49                 int64_t prev_frame, 
50                 int64_t next_frame, 
51                 int64_t current_frame);
52         void reset(int do_mode);
54         int input_min[5];
55         int input_mid[5];
56         int input_max[5];
57         int output_min[5];
58         int output_max[5];
59         int automatic;
60         int mode;
61         int threshold;
66 class HistogramSlider : public BC_SubWindow
68 public:
69         HistogramSlider(HistogramMain *plugin, 
70                 HistogramWindow *gui,
71                 int x, 
72                 int y, 
73                 int w,
74                 int h,
75                 int is_input);
77         void update();
78         int button_press_event();
79         int button_release_event();
80         int cursor_motion_event();
82         int operation;
83         enum
84         {
85                 NONE,
86                 DRAG_MIN_INPUT,
87                 DRAG_MID_INPUT,
88                 DRAG_MAX_INPUT,
89                 DRAG_MIN_OUTPUT,
90                 DRAG_MAX_OUTPUT,
91         };
92         int is_input;
93         HistogramMain *plugin;
94         HistogramWindow *gui;
97 class HistogramAuto : public BC_CheckBox
99 public:
100         HistogramAuto(HistogramMain *plugin, 
101                 int x, 
102                 int y);
103         int handle_event();
104         HistogramMain *plugin;
107 class HistogramMode : public BC_Radial
109 public:
110         HistogramMode(HistogramMain *plugin, 
111                 int x, 
112                 int y,
113                 int value,
114                 char *text);
115         int handle_event();
116         HistogramMain *plugin;
117         int value;
120 class HistogramReset : public BC_GenericButton
122 public:
123         HistogramReset(HistogramMain *plugin, 
124                 int x,
125                 int y);
126         int handle_event();
127         HistogramMain *plugin;
130 class HistogramText : public BC_TumbleTextBox
132 public:
133         HistogramText(HistogramMain *plugin,
134                 HistogramWindow *gui,
135                 int x,
136                 int y,
137                 int *output);
138         int handle_event();
139         HistogramMain *plugin;
140         int *output;
143 class HistogramWindow : public BC_Window
145 public:
146         HistogramWindow(HistogramMain *plugin, int x, int y);
147         ~HistogramWindow();
149         int create_objects();
150         int close_event();
151         void update(int do_input);
152         void update_mode();
153         void update_canvas();
154         void update_input();
155         void update_output();
157         HistogramSlider *input, *output;
158         HistogramAuto *automatic;
159         HistogramMode *mode_v, *mode_r, *mode_g, *mode_b,  *mode_a;
160         HistogramText *input_min;
161         HistogramText *input_mid;
162         HistogramText *input_max;
163         HistogramText *output_min;
164         HistogramText *output_max;
165         HistogramText *threshold;
166         BC_SubWindow *canvas;
167         HistogramMain *plugin;
168         BC_Pixmap *max_picon, *mid_picon, *min_picon;
173 PLUGIN_THREAD_HEADER(HistogramMain, HistogramThread, HistogramWindow)
176 class HistogramMain : public PluginVClient
178 public:
179         HistogramMain(PluginServer *server);
180         ~HistogramMain();
182         int process_realtime(VFrame *input_ptr, VFrame *output_ptr);
183         int is_realtime();
184         int load_defaults();
185         int save_defaults();
186         void save_data(KeyFrame *keyframe);
187         void read_data(KeyFrame *keyframe);
188         void update_gui();
189         void render_gui(void *data);
190         PLUGIN_CLASS_MEMBERS(HistogramConfig, HistogramThread)
192 // Convert input to input curve
193         float calculate_curve(float input, int mode);
194 // Calculate automatic settings
195         void calculate_automatic(VFrame *data);
196 // Calculate histogram
197         void calculate_histogram(VFrame *data);
201         YUV yuv;
202         VFrame *input, *output;
203         HistogramEngine *engine;
204         int *lookup[4];
205         int64_t *accum[5];
208 class HistogramPackage : public LoadPackage
210 public:
211         HistogramPackage();
212         int start, end;
215 class HistogramUnit : public LoadClient
217 public:
218         HistogramUnit(HistogramEngine *server, HistogramMain *plugin);
219         ~HistogramUnit();
220         void process_package(LoadPackage *package);
221         HistogramEngine *server;
222         HistogramMain *plugin;
223         int64_t *accum[5];
226 class HistogramEngine : public LoadServer
228 public:
229         HistogramEngine(HistogramMain *plugin, 
230                 int total_clients, 
231                 int total_packages);
232         void process_packages(int operation, VFrame *data);
233         void init_packages();
234         LoadClient* new_client();
235         LoadPackage* new_package();
236         HistogramMain *plugin;
238         int operation;
239         enum
240         {
241                 HISTOGRAM,
242                 TABULATE,
243                 APPLY
244         };
245         VFrame *data;
266 REGISTER_PLUGIN(HistogramMain)
270 HistogramConfig::HistogramConfig()
272         reset(1);
275 void HistogramConfig::reset(int do_mode)
277         for(int i = 0; i < 5; i++)
278         {
279                 input_min[i] = 0;
280                 input_mid[i] = 0x8000;
281                 input_max[i] = 0xffff;
282                 output_min[i] = 0;
283                 output_max[i] = 0xffff;
284         }
285         if(do_mode) 
286         {
287                 mode = HISTOGRAM_VALUE;
288                 automatic = 0;
289                 threshold = 10;
290         }
293 int HistogramConfig::equivalent(HistogramConfig &that)
295         for(int i = 0; i < 5; i++)
296         {
297                 if(input_min[i] != that.input_min[i] ||
298                         input_mid[i] != that.input_mid[i] ||
299                         input_max[i] != that.input_max[i] ||
300                         output_min[i] != that.output_min[i] ||
301                         output_max[i] != that.output_max[i]) return 0;
302         }
304         if(automatic != that.automatic ||
305                 mode != that.mode ||
306                 threshold != that.threshold) return 0;
308         return 1;
311 void HistogramConfig::copy_from(HistogramConfig &that)
313         for(int i = 0; i < 5; i++)
314         {
315                 input_min[i] = that.input_min[i];
316                 input_mid[i] = that.input_mid[i];
317                 input_max[i] = that.input_max[i];
318                 output_min[i] = that.output_min[i];
319                 output_max[i] = that.output_max[i];
320         }
322         automatic = that.automatic;
323         mode = that.mode;
324         threshold = that.threshold;
327 void HistogramConfig::interpolate(HistogramConfig &prev, 
328         HistogramConfig &next, 
329         int64_t prev_frame, 
330         int64_t next_frame, 
331         int64_t current_frame)
333         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
334         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
336         for(int i = 0; i < 5; i++)
337         {
338                 input_min[i] = (int)(prev.input_min[i] * prev_scale + next.input_min[i] * next_scale);
339                 input_mid[i] = (int)(prev.input_mid[i] * prev_scale + next.input_mid[i] * next_scale);
340                 input_max[i] = (int)(prev.input_max[i] * prev_scale + next.input_max[i] * next_scale);
341                 output_min[i] = (int)(prev.output_min[i] * prev_scale + next.output_min[i] * next_scale);
342                 output_max[i] = (int)(prev.output_max[i] * prev_scale + next.output_max[i] * next_scale);
343         }
344         threshold = (int)(prev.threshold * prev_scale + next.threshold * next_scale);
345         automatic = prev.automatic;
346         mode = prev.mode;
355 PLUGIN_THREAD_OBJECT(HistogramMain, HistogramThread, HistogramWindow)
359 HistogramWindow::HistogramWindow(HistogramMain *plugin, int x, int y)
360  : BC_Window(plugin->gui_string, 
361         x,
362         y,
363         440, 
364         480, 
365         440, 
366         480, 
367         0, 
368         1)
370         this->plugin = plugin; 
373 HistogramWindow::~HistogramWindow()
377 static VFrame max_picon_image(max_picon_png);
378 static VFrame mid_picon_image(mid_picon_png);
379 static VFrame min_picon_image(min_picon_png);
381 int HistogramWindow::create_objects()
383         int x = 10, y = 10, x1 = 10;
384         int subscript = plugin->config.mode;
386         max_picon = new BC_Pixmap(this, &max_picon_image);
387         mid_picon = new BC_Pixmap(this, &mid_picon_image);
388         min_picon = new BC_Pixmap(this, &min_picon_image);
389         add_subwindow(mode_v = new HistogramMode(plugin, 
390                 x, 
391                 y,
392                 HISTOGRAM_VALUE,
393                 _("Value")));
394         x += 70;
395         add_subwindow(mode_r = new HistogramMode(plugin, 
396                 x, 
397                 y,
398                 HISTOGRAM_RED,
399                 _("Red")));
400         x += 70;
401         add_subwindow(mode_g = new HistogramMode(plugin, 
402                 x, 
403                 y,
404                 HISTOGRAM_GREEN,
405                 _("Green")));
406         x += 70;
407         add_subwindow(mode_b = new HistogramMode(plugin, 
408                 x, 
409                 y,
410                 HISTOGRAM_BLUE,
411                 _("Blue")));
412         x += 70;
413         add_subwindow(mode_a = new HistogramMode(plugin, 
414                 x, 
415                 y,
416                 HISTOGRAM_ALPHA,
417                 _("Alpha")));
419         x = x1;
420         y += 30;
421         add_subwindow(new BC_Title(x, y, _("Input min:")));
422         x += 80;
423         input_min = new HistogramText(plugin,
424                 this,
425                 x,
426                 y,
427                 &plugin->config.input_min[subscript]);
428         input_min->create_objects();
429         x += 90;
430         add_subwindow(new BC_Title(x, y, _("Mid:")));
431         x += 40;
432         input_mid = new HistogramText(plugin,
433                 this,
434                 x,
435                 y,
436                 &plugin->config.input_mid[subscript]);
437         input_mid->create_objects();
438         input_mid->update((int64_t)plugin->config.input_mid[subscript]);
439         x += 90;
440         add_subwindow(new BC_Title(x, y, _("Max:")));
441         x += 40;
442         input_max = new HistogramText(plugin,
443                 this,
444                 x,
445                 y,
446                 &plugin->config.input_max[subscript]);
447         input_max->create_objects();
449         x = x1;
450         y += 30;
451         add_subwindow(canvas = new BC_SubWindow(x, 
452                 y, 
453                 get_w() - x - x, 
454                 get_h() - y - 150,
455                 0xffffff));
457         y += canvas->get_h() + 10;
458         add_subwindow(input = new HistogramSlider(plugin, 
459                 this,
460                 x, 
461                 y, 
462                 get_w() - 20,
463                 30,
464                 1));
465         input->update();
467         y += input->get_h() + 10;
468         add_subwindow(new BC_Title(x, y, _("Output min:")));
469         x += 90;
470         output_min = new HistogramText(plugin,
471                 this,
472                 x,
473                 y,
474                 &plugin->config.output_min[subscript]);
475         output_min->create_objects();
476         x += 90;
477         add_subwindow(new BC_Title(x, y, _("Max:")));
478         x += 40;
479         output_max = new HistogramText(plugin,
480                 this,
481                 x,
482                 y,
483                 &plugin->config.output_max[subscript]);
484         output_max->create_objects();
486         x = x1;
487         y += 30;
491         add_subwindow(output = new HistogramSlider(plugin, 
492                 this,
493                 x, 
494                 y, 
495                 get_w() - 20,
496                 30,
497                 0));
498         output->update();
499         y += 40;
502         add_subwindow(automatic = new HistogramAuto(plugin, 
503                 x, 
504                 y));
506         x += 120;
507         add_subwindow(new HistogramReset(plugin, 
508                 x, 
509                 y));
510         x += 100;
511         add_subwindow(new BC_Title(x, y, _("Threshold:")));
512         x += 100;
513         threshold = new HistogramText(plugin,
514                 this,
515                 x,
516                 y,
517                 &plugin->config.threshold);
518         threshold->create_objects();
520         show_window();
521         flush();
522         return 0;
525 WINDOW_CLOSE_EVENT(HistogramWindow)
527 void HistogramWindow::update(int do_input)
529         automatic->update(plugin->config.automatic);
530         threshold->update((int64_t)plugin->config.threshold);
531         update_mode();
533         if(do_input) update_input();
534         update_output();
537 void HistogramWindow::update_input()
539         int subscript = plugin->config.mode;
540         input->update();
541         input_min->update((int64_t)plugin->config.input_min[subscript]);
542         input_mid->update((int64_t)plugin->config.input_mid[subscript]);
543         input_max->update((int64_t)plugin->config.input_max[subscript]);
546 void HistogramWindow::update_output()
548         int subscript = plugin->config.mode;
549         output->update();
550         output_min->update((int64_t)plugin->config.output_min[subscript]);
551         output_max->update((int64_t)plugin->config.output_max[subscript]);
554 void HistogramWindow::update_mode()
556         mode_v->update(plugin->config.mode == HISTOGRAM_VALUE ? 1 : 0);
557         mode_r->update(plugin->config.mode == HISTOGRAM_RED ? 1 : 0);
558         mode_g->update(plugin->config.mode == HISTOGRAM_GREEN ? 1 : 0);
559         mode_b->update(plugin->config.mode == HISTOGRAM_BLUE ? 1 : 0);
560         mode_a->update(plugin->config.mode == HISTOGRAM_ALPHA ? 1 : 0);
561         input_min->output = &plugin->config.input_min[plugin->config.mode];
562         input_mid->output = &plugin->config.input_mid[plugin->config.mode];
563         input_max->output = &plugin->config.input_max[plugin->config.mode];
564         output_min->output = &plugin->config.output_min[plugin->config.mode];
565         output_max->output = &plugin->config.output_max[plugin->config.mode];
568 void HistogramWindow::update_canvas()
570         int64_t *accum = plugin->accum[plugin->config.mode];
571         int canvas_w = canvas->get_w();
572         int canvas_h = canvas->get_h();
573         int accum_per_canvas_i = HISTOGRAM_RANGE / canvas_w + 1;
574         float accum_per_canvas_f = (float)HISTOGRAM_RANGE / canvas_w;
575         int normalize = 0;
576         int max = 0;
577         for(int i = 0; i < HISTOGRAM_RANGE; i++)
578         {
579                 if(accum[i] > normalize) normalize = accum[i];
580         }
583         if(normalize)
584         {
585                 for(int i = 0; i < canvas_w; i++)
586                 {
587                         int accum_start = (int)(accum_per_canvas_f * i);
588                         int accum_end = accum_start + accum_per_canvas_i;
589                         max = 0;
590                         for(int j = accum_start; j < accum_end; j++)
591                         {
592                                 max = MAX(accum[j], max);
593                         }
594 //printf("HistogramWindow::update_canvas 1 %d %d\n", i, max);
596 //                      max = max * canvas_h / normalize;
597                         max = (int)(log(max) / log(normalize) * canvas_h);
600                         canvas->set_color(0xffffff);
601                         canvas->draw_line(i, 0, i, canvas_h - max);
602                         canvas->set_color(0x000000);
603                         canvas->draw_line(i, canvas_h - max, i, canvas_h);
604                 }
605         }
606         else
607         {
608                 canvas->set_color(0xffffff);
609                 canvas->draw_box(0, 0, canvas_w, canvas_h);
610         }
612         canvas->set_color(0x00ff00);
613         int y1;
614         for(int i = 0; i < canvas_w; i++)
615         {
616                 int y2 = canvas_h - (int)(plugin->calculate_curve((float)i / canvas_w * (HISTOGRAM_RANGE - 1), 
617                         plugin->config.mode) * canvas_h / (HISTOGRAM_RANGE - 1));
618                 if(i > 0)
619                 {
620                         canvas->draw_line(i - 1, y1, i, y2);
621                 }
622                 y1 = y2;
623         }
625         canvas->flash();
635 HistogramReset::HistogramReset(HistogramMain *plugin, 
636         int x,
637         int y)
638  : BC_GenericButton(x, y, _("Reset"))
640         this->plugin = plugin;
642 int HistogramReset::handle_event()
644         plugin->config.reset(0);
645         plugin->thread->window->update(1);
646         plugin->send_configure_change();
647         return 1;
658 HistogramSlider::HistogramSlider(HistogramMain *plugin, 
659         HistogramWindow *gui,
660         int x, 
661         int y, 
662         int w,
663         int h,
664         int is_input)
665  : BC_SubWindow(x, y, w, h)
667         this->plugin = plugin;
668         this->gui = gui;
669         this->is_input = is_input;
670         operation = NONE;
673 int HistogramSlider::button_press_event()
675         if(is_event_win() && cursor_inside())
676         {
677                 int subscript = plugin->config.mode;
678                 int min;
679                 int max;
680                 int w = get_w();
681                 int h = get_h();
682                 int half_h = get_h() / 2;
684                 if(is_input)
685                 {
686                         int x1 = (int)(plugin->config.input_mid[subscript] * w / 0xffff) - 
687                                 gui->mid_picon->get_w() / 2;
688                         int x2 = x1 + gui->mid_picon->get_w();
689                         if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
690                                 get_cursor_y() >= half_h && get_cursor_y() < h)
691                         {
692                                 operation = DRAG_MID_INPUT;
693                         }
694                 }
696                 if(operation == NONE)
697                 {
698                         if(is_input)
699                         {
700                                 int x1 = (int)(plugin->config.input_min[subscript] * w / 0xffff) - 
701                                         gui->mid_picon->get_w() / 2;
702                                 int x2 = x1 + gui->mid_picon->get_w();
703                                 if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
704                                         get_cursor_y() >= half_h && get_cursor_y() < h)
705                                 {
706                                         operation = DRAG_MIN_INPUT;
707                                 }
708                         }
709                         else
710                         {
711                                 int x1 = (int)(plugin->config.output_min[subscript] * w / 0xffff) - 
712                                         gui->mid_picon->get_w() / 2;
713                                 int x2 = x1 + gui->mid_picon->get_w();
714                                 if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
715                                         get_cursor_y() >= half_h && get_cursor_y() < h)
716                                 {
717                                         operation = DRAG_MIN_OUTPUT;
718                                 }
719                         }
720                 }
722                 if(operation == NONE)
723                 {
724                         if(is_input)
725                         {
726                                 int x1 = (int)(plugin->config.input_max[subscript] * w / 0xffff) - 
727                                         gui->mid_picon->get_w() / 2;
728                                 int x2 = x1 + gui->mid_picon->get_w();
729                                 if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
730                                         get_cursor_y() >= half_h && get_cursor_y() < h)
731                                 {
732                                         operation = DRAG_MAX_INPUT;
733                                 }
734                         }
735                         else
736                         {
737                                 int x1 = (int)(plugin->config.output_max[subscript] * w / 0xffff) - 
738                                         gui->mid_picon->get_w() / 2;
739                                 int x2 = x1 + gui->mid_picon->get_w();
740                                 if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
741                                         get_cursor_y() >= half_h && get_cursor_y() < h)
742                                 {
743                                         operation = DRAG_MAX_OUTPUT;
744                                 }
745                         }
746                 }
747                 return 1;
748         }
749         return 0;
752 int HistogramSlider::button_release_event()
754         if(operation != NONE)
755         {
756                 operation = NONE;
757                 return 1;
758         }
759         return 0;
762 int HistogramSlider::cursor_motion_event()
764 //printf("HistogramSlider::cursor_motion_event 1\n");
765         if(operation != NONE)
766         {
767                 float value = (float)get_cursor_x() * 0xffff / get_w();
768                 CLAMP(value, 0, 0xffff);
769                 int subscript = plugin->config.mode;
770                 float input_min = plugin->config.input_min[subscript];
771                 float input_max = plugin->config.input_max[subscript];
772                 float input_mid = plugin->config.input_mid[subscript];
773                 float input_mid_fraction = (input_mid - input_min) / (input_max - input_min);
775                 switch(operation)
776                 {
777                         case DRAG_MIN_INPUT:
778                                 input_min = MIN(input_max, value);
779                                 plugin->config.input_min[subscript] = (int)input_min;
780                                 input_mid = input_min + (input_max - input_min) * input_mid_fraction;
781                                 break;
782                         case DRAG_MID_INPUT:
783                                 CLAMP(value, input_min, input_max);
784                                 input_mid = (int)value;
785                                 break;
786                         case DRAG_MAX_INPUT:
787                                 input_max = MAX(input_mid, value);
788                                 input_mid = input_min + (input_max - input_min) * input_mid_fraction;
789                                 break;
790                         case DRAG_MIN_OUTPUT:
791                                 value = MIN(plugin->config.output_max[subscript], value);
792                                 plugin->config.output_min[subscript] = (int)value;
793                                 break;
794                         case DRAG_MAX_OUTPUT:
795                                 value = MAX(plugin->config.output_min[subscript], value);
796                                 plugin->config.output_max[subscript] = (int)value;
797                                 break;
798                 }
799         
800                 if(operation == DRAG_MIN_INPUT ||
801                         operation == DRAG_MID_INPUT ||
802                         operation == DRAG_MAX_INPUT)
803                 {
804                         plugin->config.input_mid[subscript] = (int)input_mid;
805                         plugin->config.input_min[subscript] = (int)input_min;
806                         plugin->config.input_max[subscript] = (int)input_max;
807                         gui->update_input();
808                 }
809                 else
810                 {
811                         gui->update_output();
812                 }
814                 gui->unlock_window();
815                 plugin->send_configure_change();
816 //printf("HistogramSlider::cursor_motion_event 2\n");
817                 gui->lock_window("HistogramSlider::cursor_motion_event");
818 //printf("HistogramSlider::cursor_motion_event 3\n");
819                 return 1;
820         }
821         return 0;
824 void HistogramSlider::update()
826         int w = get_w();
827         int h = get_h();
828         int half_h = get_h() / 2;
829         int quarter_h = get_h() / 4;
830         int mode = plugin->config.mode;
831         int r = 0xff;
832         int g = 0xff;
833         int b = 0xff;
834         int subscript = plugin->config.mode;
836         clear_box(0, 0, w, h);
838         switch(mode)
839         {
840                 case HISTOGRAM_RED:
841                         g = b = 0x00;
842                         break;
843                 case HISTOGRAM_GREEN:
844                         r = b = 0x00;
845                         break;
846                 case HISTOGRAM_BLUE:
847                         r = g = 0x00;
848                         break;
849         }
851         for(int i = 0; i < w; i++)
852         {
853                 int color = (int)(i * 0xff / w);
854                 set_color(((r * color / 0xff) << 16) | 
855                         ((g * color / 0xff) << 8) | 
856                         (b * color / 0xff));
858                 if(is_input)
859                 {
860                         draw_line(i, quarter_h, i, half_h);
861                         color = (int)plugin->calculate_curve(i * 0xffff / w, 
862                                 subscript);
863                         set_color(((r * color / 0xffff) << 16) | 
864                                 ((g * color / 0xffff) << 8) | 
865                                 (b * color / 0xffff));
866                         draw_line(i, 0, i, quarter_h);
867                 }
868                 else
869                         draw_line(i, 0, i, half_h);
871         }
873         int min;
874         int max;
875         if(is_input)
876         {
877                 
878                 draw_pixmap(gui->mid_picon,
879                         (int)(plugin->config.input_mid[subscript] * w / 0xffff) - 
880                                 gui->mid_picon->get_w() / 2,
881                         half_h + 1);
882                 min = plugin->config.input_min[subscript];
883                 max = plugin->config.input_max[subscript];
884         }
885         else
886         {
887                 min = plugin->config.output_min[subscript];
888                 max = plugin->config.output_max[subscript];
889         }
891         draw_pixmap(gui->min_picon,
892                 min * w / 0xffff - gui->min_picon->get_w() / 2,
893                 half_h + 1);
894         draw_pixmap(gui->max_picon,
895                 max * w / 0xffff - gui->max_picon->get_w() / 2,
896                 half_h + 1);
898 // printf("HistogramSlider::update %d %d\n", min, max);
899         flash();
900         flush();
911 HistogramAuto::HistogramAuto(HistogramMain *plugin, 
912         int x, 
913         int y)
914  : BC_CheckBox(x, y, plugin->config.automatic, _("Automatic"))
916         this->plugin = plugin;
919 int HistogramAuto::handle_event()
921         plugin->config.automatic = get_value();
922         plugin->send_configure_change();
923         return 1;
929 HistogramMode::HistogramMode(HistogramMain *plugin, 
930         int x, 
931         int y,
932         int value,
933         char *text)
934  : BC_Radial(x, y, plugin->config.mode == value, text)
936         this->plugin = plugin;
937         this->value = value;
939 int HistogramMode::handle_event()
941         plugin->config.mode = value;
942         plugin->thread->window->update_mode();
943         plugin->thread->window->input->update();
944         plugin->thread->window->output->update();
945         plugin->send_configure_change();
946         return 1;
957 HistogramText::HistogramText(HistogramMain *plugin,
958         HistogramWindow *gui,
959         int x,
960         int y,
961         int *output)
962  : BC_TumbleTextBox(gui, 
963                 (int64_t)*output,
964                 (int64_t)0,
965                 (int64_t)0xff,
966                 x, 
967                 y, 
968                 60)
970         this->plugin = plugin;
971         this->output = output;
975 int HistogramText::handle_event()
977         if(output)
978         {
979                 *output = atol(get_text());
980         }
981         plugin->thread->window->input->update();
982         plugin->thread->window->output->update();
983         plugin->send_configure_change();
984         return 1;
1008 HistogramMain::HistogramMain(PluginServer *server)
1009  : PluginVClient(server)
1011         PLUGIN_CONSTRUCTOR_MACRO
1012         engine = 0;
1013         lookup[0] = lookup[1] = lookup[2] = lookup[3] = 0;
1014         accum[0] = accum[1] = accum[2] = accum[3] = accum[3] = 0;
1017 HistogramMain::~HistogramMain()
1019         PLUGIN_DESTRUCTOR_MACRO
1020         if(lookup[0]) delete [] lookup[0];
1021         if(lookup[1]) delete [] lookup[1];
1022         if(lookup[2]) delete [] lookup[2];
1023         if(lookup[3]) delete [] lookup[3];
1024         if(accum[0]) delete [] accum[0];
1025         if(accum[1]) delete [] accum[1];
1026         if(accum[2]) delete [] accum[2];
1027         if(accum[3]) delete [] accum[3];
1028         if(accum[4]) delete [] accum[4];
1029         if(engine) delete engine;
1032 char* HistogramMain::plugin_title() { return _("Histogram"); }
1033 int HistogramMain::is_realtime() { return 1; }
1036 NEW_PICON_MACRO(HistogramMain)
1038 SHOW_GUI_MACRO(HistogramMain, HistogramThread)
1040 SET_STRING_MACRO(HistogramMain)
1042 RAISE_WINDOW_MACRO(HistogramMain)
1044 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
1046 void HistogramMain::render_gui(void *data)
1048         if(thread)
1049         {
1050                 calculate_histogram((VFrame*)data);
1051                 if(config.automatic)
1052                 {
1053                         calculate_automatic((VFrame*)data);
1054                 }
1056                 thread->window->lock_window("HistogramMain::render_gui");
1057                 thread->window->update_canvas();
1058                 if(config.automatic)
1059                 {
1060                         thread->window->update_input();
1061                 }
1062                 thread->window->unlock_window();
1063         }
1066 void HistogramMain::update_gui()
1068         if(thread)
1069         {
1070                 thread->window->lock_window("HistogramMain::update_gui");
1071                 int reconfigure = load_configuration();
1072                 if(reconfigure) 
1073                 {
1074                         thread->window->update(0);
1075                         if(!config.automatic)
1076                         {
1077                                 thread->window->update_input();
1078                         }
1079                 }
1080                 thread->window->unlock_window();
1081         }
1085 int HistogramMain::load_defaults()
1087         char directory[BCTEXTLEN], string[BCTEXTLEN];
1088 // set the default directory
1089         sprintf(directory, "%shistogram.rc", BCASTDIR);
1091 // load the defaults
1092         defaults = new Defaults(directory);
1093         defaults->load();
1095         for(int i = 0; i < 5; i++)
1096         {
1097                 sprintf(string, "INPUT_MIN_%d", i);
1098                 config.input_min[i] = defaults->get(string, config.input_min[i]);
1099                 sprintf(string, "INPUT_MID_%d", i);
1100                 config.input_mid[i] = defaults->get(string, config.input_mid[i]);
1101                 sprintf(string, "INPUT_MAX_%d", i);
1102                 config.input_max[i] = defaults->get(string, config.input_max[i]);
1103                 sprintf(string, "OUTPUT_MIN_%d", i);
1104                 config.output_min[i] = defaults->get(string, config.output_min[i]);
1105                 sprintf(string, "OUTPUT_MAX_%d", i);
1106                 config.output_max[i] = defaults->get(string, config.output_max[i]);
1107 //printf("HistogramMain::load_defaults %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
1108         }
1109         config.automatic = defaults->get("AUTOMATIC", config.automatic);
1110         config.mode = defaults->get("MODE", config.mode);
1111         config.threshold = defaults->get("THRESHOLD", config.threshold);
1112         return 0;
1116 int HistogramMain::save_defaults()
1118         char string[BCTEXTLEN];
1119 //printf("HistogramMain::save_defaults 1 %p\n", defaults);
1120         for(int i = 0; i < 5; i++)
1121         {
1122 //printf("HistogramMain::save_defaults 1 %d\n", i);
1123                 sprintf(string, "INPUT_MIN_%d", i);
1124                 defaults->update(string, config.input_min[i]);
1125 //printf("HistogramMain::save_defaults 1 %d\n", i);
1126                 sprintf(string, "INPUT_MID_%d", i);
1127                 defaults->update(string, config.input_mid[i]);
1128 //printf("HistogramMain::save_defaults 1 %d\n", i);
1129                 sprintf(string, "INPUT_MAX_%d", i);
1130 //printf("HistogramMain::save_defaults 1 %d\n", config.input_max[i]);
1131                 defaults->update(string, config.input_max[i]);
1132 //printf("HistogramMain::save_defaults 1 %d\n", i);
1133                 sprintf(string, "OUTPUT_MIN_%d", i);
1134                 defaults->update(string, config.output_min[i]);
1135 //printf("HistogramMain::save_defaults 1 %d\n", i);
1136                 sprintf(string, "OUTPUT_MAX_%d", i);
1137                 defaults->update(string, config.output_max[i]);
1138 //printf("HistogramMain::save_defaults %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
1139         }
1140 //printf("HistogramMain::save_defaults 3\n");
1141         defaults->update("AUTOMATIC", config.automatic);
1142 //printf("HistogramMain::save_defaults 4\n");
1143         defaults->update("MODE", config.mode);
1144         defaults->update("THRESHOLD", config.threshold);
1145 //printf("HistogramMain::save_defaults 5\n");
1146         defaults->save();
1147 //printf("HistogramMain::save_defaults 6\n");
1148         return 0;
1153 void HistogramMain::save_data(KeyFrame *keyframe)
1155         FileXML output;
1157 // cause data to be stored directly in text
1158         output.set_shared_string(keyframe->data, MESSAGESIZE);
1159         output.tag.set_title("HISTOGRAM");
1161         char string[BCTEXTLEN];
1162         for(int i = 0; i < 5; i++)
1163         {
1164                 sprintf(string, "INPUT_MIN_%d", i);
1165                 output.tag.set_property(string, config.input_min[i]);
1166                 sprintf(string, "INPUT_MID_%d", i);
1167                 output.tag.set_property(string, config.input_mid[i]);
1168                 sprintf(string, "INPUT_MAX_%d", i);
1169                 output.tag.set_property(string, config.input_max[i]);
1170                 sprintf(string, "OUTPUT_MIN_%d", i);
1171                 output.tag.set_property(string, config.output_min[i]);
1172                 sprintf(string, "OUTPUT_MAX_%d", i);
1173                 output.tag.set_property(string, config.output_max[i]);
1174 //printf("HistogramMain::save_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
1175         }
1176         output.tag.set_property("AUTOMATIC", config.automatic);
1177         output.tag.set_property("MODE", config.mode);
1178         output.tag.set_property("THRESHOLD", config.threshold);
1179         output.append_tag();
1180         output.terminate_string();
1183 void HistogramMain::read_data(KeyFrame *keyframe)
1185         FileXML input;
1187         input.set_shared_string(keyframe->data, strlen(keyframe->data));
1189         int result = 0;
1191         while(!result)
1192         {
1193                 result = input.read_tag();
1195                 if(!result)
1196                 {
1197                         if(input.tag.title_is("HISTOGRAM"))
1198                         {
1199                                 char string[BCTEXTLEN];
1200                                 for(int i = 0; i < 5; i++)
1201                                 {
1202                                         sprintf(string, "INPUT_MIN_%d", i);
1203                                         config.input_min[i] = input.tag.get_property(string, config.input_min[i]);
1204                                         sprintf(string, "INPUT_MID_%d", i);
1205                                         config.input_mid[i] = input.tag.get_property(string, config.input_mid[i]);
1206                                         sprintf(string, "INPUT_MAX_%d", i);
1207                                         config.input_max[i] = input.tag.get_property(string, config.input_max[i]);
1208                                         sprintf(string, "OUTPUT_MIN_%d", i);
1209                                         config.output_min[i] = input.tag.get_property(string, config.output_min[i]);
1210                                         sprintf(string, "OUTPUT_MAX_%d", i);
1211                                         config.output_max[i] = input.tag.get_property(string, config.output_max[i]);
1212 //printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
1213                                 }
1214                                 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
1215                                 config.mode = input.tag.get_property("MODE", config.mode);
1216                                 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
1217                         }
1218                 }
1219         }
1222 float HistogramMain::calculate_curve(float input, int subscript)
1224         float y1, y2, y3, y4;
1225         float min = (float)config.input_min[subscript];
1226         float max = (float)config.input_max[subscript];
1227         float mid = (float)config.input_mid[subscript];
1228         float half = (float)HISTOGRAM_RANGE / 2;
1229         float output, output_perfect;
1230         float control = 1.0 / M_PI;
1231         float output_linear;
1233 // Below minimum
1234         if(input < min) return 0;
1236 // Above maximum
1237         if(input >= max) return HISTOGRAM_RANGE - 1;
1239         float slope1 = half / (mid - min);
1240         float slope2 = half / (max - mid);
1241         float min_slope = MIN(slope1, slope2);
1243 // value of 45` diagonal with midpoint
1244         output_perfect = half + min_slope * (input - mid);
1245 // Left hand side
1246         if(input < mid)
1247         {
1248 // Fraction of perfect diagonal to use
1249                 float mid_fraction = (input - min) / (mid - min);
1250 // value of line connecting min to mid
1251                 output_linear = mid_fraction * half;
1252 // Blend perfect diagonal with linear
1253                 output = output_linear * (1.0 - mid_fraction) + output_perfect * mid_fraction;
1254         }
1255         else
1256         {
1257 // Fraction of perfect diagonal to use
1258                 float mid_fraction = (max - input) / (max - mid);
1259 // value of line connecting max to mid
1260                 output_linear = half + (1.0 - mid_fraction) * half;
1261 // Blend perfect diagonal with linear
1262                 output = output_linear * (1.0 - mid_fraction) + output_perfect * mid_fraction;
1263         }
1271 // printf("HistogramMain::calculate_curve 1 %.0f %.0f %.0f %.0f %.0f\n",
1272 // output, 
1273 // input,
1274 // min,
1275 // mid,
1276 // max);
1277         return output;
1280 void HistogramMain::calculate_histogram(VFrame *data)
1283         if(!engine) engine = new HistogramEngine(this,
1284                 get_project_smp() + 1,
1285                 get_project_smp() + 1);
1287         if(!accum[0])
1288         {
1289                 for(int i = 0; i < 5; i++)
1290                         accum[i] = new int64_t[HISTOGRAM_RANGE];
1291         }
1292         engine->process_packages(HistogramEngine::HISTOGRAM, data);
1294         for(int i = 0; i < engine->get_total_clients(); i++)
1295         {
1296                 HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
1297                 if(i == 0)
1298                 {
1299                         for(int j = 0; j < 5; j++)
1300                                 memcpy(accum[j], unit->accum[j], sizeof(int64_t) * HISTOGRAM_RANGE);
1301                 }
1302                 else
1303                 {
1304                         for(int j = 0; j < 5; j++)
1305                         {
1306                                 int64_t *out = accum[j];
1307                                 int64_t *in = unit->accum[j];
1308                                 for(int k = 0; k < HISTOGRAM_RANGE; k++)
1309                                         out[k] += in[k];
1310                         }
1311                 }
1312         }
1314 // Remove top and bottom from calculations.  Doesn't work in high
1315 // precision colormodels.
1316         for(int i = 0; i < 5; i++)
1317         {
1318                 accum[i][0] = 0;
1319                 accum[i][HISTOGRAM_RANGE - 1] = 0;
1320         }
1324 void HistogramMain::calculate_automatic(VFrame *data)
1326         calculate_histogram(data);
1329         for(int i = 0; i < 3; i++)
1330         {
1331                 int64_t *accum = this->accum[i];
1332                 int max = 0;
1334                 for(int j = 0; j < HISTOGRAM_RANGE; j++)
1335                 {
1336                         max = MAX(accum[j], max);
1337                 }
1339                 int threshold = config.threshold * max / THRESHOLD_SCALE;
1342 // Minimums
1343                 config.input_min[i] = 0;
1344                 for(int j = 0; j < HISTOGRAM_RANGE; j++)
1345                 {
1346                         if(accum[j] > threshold)
1347                         {
1348                                 config.input_min[i] = j;
1349                                 break;
1350                         }
1351                 }
1354 // Maximums
1355                 config.input_max[i] = 0xffff;
1356                 for(int j = HISTOGRAM_RANGE - 1; j >= 0; j--)
1357                 {
1358                         if(accum[j] > threshold)
1359                         {
1360                                 config.input_max[i] = j;
1361                                 break;
1362                         }
1363                 }
1365                 config.input_mid[i] = (config.input_min[i] + config.input_max[i]) / 2;
1366         }
1374 int HistogramMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
1376 TRACE("HistogramMain::process_realtime");
1377         int need_reconfigure = load_configuration();
1380         if(!engine) engine = new HistogramEngine(this,
1381                 get_project_smp() + 1,
1382                 get_project_smp() + 1);
1383         this->input = input_ptr;
1384         this->output = output_ptr;
1386         send_render_gui(input_ptr);
1388         if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
1389         {
1390                 output_ptr->copy_from(input_ptr);
1391         }
1392 //printf("HistogramMain::process_realtime 1\n");
1394 // Generate tables here.  The same table is used by many packages to render
1395 // each horizontal stripe.  Need to cover the entire output range in  each
1396 // table to avoid green borders
1397         if(need_reconfigure || !lookup[0] || config.automatic)
1398         {
1399                 if(!lookup[0])
1400                         for(int i = 0; i < 4; i++)
1401                                 lookup[i] = new int[HISTOGRAM_RANGE];
1403 // Calculate new curves
1404                 if(config.automatic)
1405                 {
1406                         calculate_automatic(input);
1407                 }
1409                 engine->process_packages(HistogramEngine::TABULATE, input);
1413 // Convert 16 bit lookup table to 8 bits
1414                 switch(input->get_color_model())
1415                 {
1416                         case BC_RGB888:
1417                         case BC_RGBA8888:
1418                                 for(int i = 0; i < 0x100; i++)
1419                                 {
1420                                         int subscript = (i << 8) | i;
1421                                         lookup[0][i] = lookup[0][subscript];
1422                                         lookup[1][i] = lookup[1][subscript];
1423                                         lookup[2][i] = lookup[2][subscript];
1424                                         lookup[3][i] = lookup[3][subscript];
1425                                 }
1426                                 break;
1427                 }
1428         }
1429 //printf("HistogramMain::process_realtime 1\n");
1434 // Apply histogram
1435         engine->process_packages(HistogramEngine::APPLY, input);
1437 //printf("HistogramMain::process_realtime 100\n");
1440 UNTRACE
1442         return 0;
1450 HistogramPackage::HistogramPackage()
1451  : LoadPackage()
1458 HistogramUnit::HistogramUnit(HistogramEngine *server, 
1459         HistogramMain *plugin)
1460  : LoadClient(server)
1462         this->plugin = plugin;
1463         this->server = server;
1464         for(int i = 0; i < 5; i++)
1465                 accum[i] = new int64_t[HISTOGRAM_RANGE];
1468 HistogramUnit::~HistogramUnit()
1470         for(int i = 0; i < 5; i++)
1471                 delete [] accum[i];
1474 void HistogramUnit::process_package(LoadPackage *package)
1476         HistogramPackage *pkg = (HistogramPackage*)package;
1478         if(server->operation == HistogramEngine::HISTOGRAM)
1479         {
1481 #define HISTOGRAM_HEAD(type) \
1482 { \
1483         for(int i = pkg->start; i < pkg->end; i++) \
1484         { \
1485                 type *row = (type*)data->get_rows()[i]; \
1486                 for(int j = 0; j < w; j++) \
1487                 {
1489 #define HISTOGRAM_TAIL(components) \
1490                         v = MAX(r, g); \
1491                         v = MAX(v, b); \
1492                         accum_r[r]++; \
1493                         accum_g[g]++; \
1494                         accum_b[b]++; \
1495                         if(components == 4) accum_a[row[3]]++; \
1496                         accum_v[v]++; \
1497                         row += components; \
1498                 } \
1499         } \
1505                 VFrame *data = server->data;
1506                 int w = data->get_w();
1507                 int h = data->get_h();
1508                 int64_t *accum_r = accum[HISTOGRAM_RED];
1509                 int64_t *accum_g = accum[HISTOGRAM_GREEN];
1510                 int64_t *accum_b = accum[HISTOGRAM_BLUE];
1511                 int64_t *accum_a = accum[HISTOGRAM_ALPHA];
1512                 int64_t *accum_v = accum[HISTOGRAM_VALUE];
1513                 int r, g, b, a, y, u, v;
1515                 switch(data->get_color_model())
1516                 {
1517                         case BC_RGB888:
1518                                 HISTOGRAM_HEAD(unsigned char)
1519                                 r = (row[0] << 8) | row[0];
1520                                 g = (row[1] << 8) | row[1];
1521                                 b = (row[2] << 8) | row[2];
1522                                 HISTOGRAM_TAIL(3)
1523                                 break;
1524                         case BC_YUV888:
1525                                 HISTOGRAM_HEAD(unsigned char)
1526                                 y = (row[0] << 8) | row[0];
1527                                 u = (row[1] << 8) | row[1];
1528                                 v = (row[2] << 8) | row[2];
1529                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1530                                 HISTOGRAM_TAIL(3)
1531                                 break;
1532                         case BC_RGBA8888:
1533                                 HISTOGRAM_HEAD(unsigned char)
1534                                 r = (row[0] << 8) | row[0];
1535                                 g = (row[1] << 8) | row[1];
1536                                 b = (row[2] << 8) | row[2];
1537                                 HISTOGRAM_TAIL(4)
1538                                 break;
1539                         case BC_YUVA8888:
1540                                 HISTOGRAM_HEAD(unsigned char)
1541                                 y = (row[0] << 8) | row[0];
1542                                 u = (row[1] << 8) | row[1];
1543                                 v = (row[2] << 8) | row[2];
1544                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1545                                 HISTOGRAM_TAIL(4)
1546                                 break;
1547                         case BC_RGB161616:
1548                                 HISTOGRAM_HEAD(uint16_t)
1549                                 r = row[0];
1550                                 g = row[1];
1551                                 b = row[2];
1552                                 HISTOGRAM_TAIL(3)
1553                                 break;
1554                         case BC_YUV161616:
1555                                 HISTOGRAM_HEAD(uint16_t)
1556                                 y = row[0];
1557                                 u = row[1];
1558                                 v = row[2];
1559                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1560                                 HISTOGRAM_TAIL(3)
1561                                 break;
1562                         case BC_RGBA16161616:
1563                                 HISTOGRAM_HEAD(uint16_t)
1564                                 r = row[0];
1565                                 g = row[1];
1566                                 b = row[2];
1567                                 HISTOGRAM_TAIL(3)
1568                                 break;
1569                         case BC_YUVA16161616:
1570                                 HISTOGRAM_HEAD(uint16_t)
1571                                 y = row[0];
1572                                 u = row[1];
1573                                 v = row[2];
1574                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1575                                 HISTOGRAM_TAIL(4)
1576                                 break;
1577                 }
1578         }
1579         else
1580         if(server->operation == HistogramEngine::APPLY)
1581         {
1585 #define PROCESS(type, components) \
1586 { \
1587         for(int i = pkg->start; i < pkg->end; i++) \
1588         { \
1589                 type *row = (type*)input->get_rows()[i]; \
1590                 for(int j = 0; j < w; j++) \
1591                 { \
1592                         row[0] = lookup_r[row[0]]; \
1593                         row[1] = lookup_g[row[1]]; \
1594                         row[2] = lookup_b[row[2]]; \
1595                         if(components == 4) row[3] = lookup_a[row[3]]; \
1596                         row += components; \
1597                 } \
1598         } \
1601 #define PROCESS_YUV(type, components, max) \
1602 { \
1603         for(int i = pkg->start; i < pkg->end; i++) \
1604         { \
1605                 type *row = (type*)input->get_rows()[i]; \
1606                 for(int j = 0; j < w; j++) \
1607                 { \
1608 /* Convert to 16 bit RGB */ \
1609                         if(max == 0xff) \
1610                         { \
1611                                 y = (row[0] << 8) | row[0]; \
1612                                 u = (row[1] << 8) | row[1]; \
1613                                 v = (row[2] << 8) | row[2]; \
1614                                 if(components == 4) a = (row[3] << 8) | row[3]; \
1615                         } \
1616                         else \
1617                         { \
1618                                 y = row[0]; \
1619                                 u = row[1]; \
1620                                 v = row[2]; \
1621                                 if(components == 4) a = row[3]; \
1622                         } \
1624                         plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
1626 /* Look up in RGB domain */ \
1627                         r = lookup_r[r]; \
1628                         g = lookup_g[g]; \
1629                         b = lookup_b[b]; \
1630                         if(components == 4) a = lookup_a[a]; \
1632 /* Convert to 16 bit YUV */ \
1633                         plugin->yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
1635                         if(max == 0xff) \
1636                         { \
1637                                 row[0] = y >> 8; \
1638                                 row[1] = u >> 8; \
1639                                 row[2] = v >> 8; \
1640                                 if(components == 4) row[3] = a >> 8; \
1641                         } \
1642                         else \
1643                         { \
1644                                 row[0] = y; \
1645                                 row[1] = u; \
1646                                 row[2] = v; \
1647                                 if(components == 4) row[3] = a; \
1648                         } \
1649                         row += components; \
1650                 } \
1651         } \
1657                 VFrame *input = plugin->input;
1658                 VFrame *output = plugin->output;
1659                 int w = input->get_w();
1660                 int h = input->get_h();
1661                 int *lookup_r = plugin->lookup[0];
1662                 int *lookup_g = plugin->lookup[1];
1663                 int *lookup_b = plugin->lookup[2];
1664                 int *lookup_a = plugin->lookup[3];
1665                 int r, g, b, y, u, v, a;
1666                 switch(input->get_color_model())
1667                 {
1668                         case BC_RGB888:
1669                                 PROCESS(unsigned char, 3)
1670                                 break;
1671                         case BC_RGBA8888:
1672                                 PROCESS(unsigned char, 4)
1673                                 break;
1674                         case BC_RGB161616:
1675                                 PROCESS(uint16_t, 3)
1676                                 break;
1677                         case BC_RGBA16161616:
1678                                 PROCESS(uint16_t, 4)
1679                                 break;
1680                         case BC_YUV888:
1681                                 PROCESS_YUV(unsigned char, 3, 0xff)
1682                                 break;
1683                         case BC_YUVA8888:
1684                                 PROCESS_YUV(unsigned char, 4, 0xff)
1685                                 break;
1686                         case BC_YUV161616:
1687                                 PROCESS_YUV(uint16_t, 3, 0xffff)
1688                                 break;
1689                         case BC_YUVA16161616:
1690                                 PROCESS_YUV(uint16_t, 4, 0xffff)
1691                                 break;
1692                 }
1693         }
1694         if(server->operation == HistogramEngine::TABULATE)
1695         {
1696 // Do conversion in 16 bit YUVA
1697                 int min_output_r = plugin->config.output_min[0];
1698                 int min_output_g = plugin->config.output_min[1];
1699                 int min_output_b = plugin->config.output_min[2];
1700                 int min_output_a = plugin->config.output_min[3];
1701                 int min_output_v = plugin->config.output_min[4];
1702                 int max_output_r = plugin->config.output_max[0];
1703                 int max_output_g = plugin->config.output_max[1];
1704                 int max_output_b = plugin->config.output_max[2];
1705                 int max_output_a = plugin->config.output_max[3];
1706                 int max_output_v = plugin->config.output_max[4];
1707                 int colormodel = plugin->input->get_color_model();
1709                 for(int i = pkg->start; i < pkg->end; i++)
1710                 {
1711 // Expand input
1712                         float r = plugin->calculate_curve((float)i, HISTOGRAM_RED);
1713                         float g = plugin->calculate_curve((float)i, HISTOGRAM_GREEN);
1714                         float b = plugin->calculate_curve((float)i, HISTOGRAM_BLUE);
1715                         float a = plugin->calculate_curve((float)i, HISTOGRAM_ALPHA);
1716                         int y, u, v;
1717 // Expand value
1718                         r = plugin->calculate_curve((float)r, HISTOGRAM_VALUE);
1719                         g = plugin->calculate_curve((float)g, HISTOGRAM_VALUE);
1720                         b = plugin->calculate_curve((float)b, HISTOGRAM_VALUE);
1721 // r = i;
1722 // g = i;
1723 // b = i;
1725 // Shrink output
1726                         r = (float)min_output_r + 
1727                                 r * 
1728                                 (max_output_r - min_output_r) / 
1729                                 (HISTOGRAM_RANGE - 1);
1730                         g = min_output_g + 
1731                                 g * 
1732                                 (max_output_g - min_output_g) / 
1733                                 (HISTOGRAM_RANGE - 1);
1734                         b = min_output_b + 
1735                                 b * 
1736                                 (max_output_b - min_output_b) / 
1737                                 (HISTOGRAM_RANGE - 1);
1738                         a = min_output_a + 
1739                                 a * 
1740                                 (max_output_a - min_output_a) / 
1741                                 (HISTOGRAM_RANGE - 1);
1742 // Shrink value
1743 //printf(" 1 %d -> ", r);
1744                         r = min_output_v + 
1745                                 r * 
1746                                 (max_output_v - min_output_v) / 
1747                                 (HISTOGRAM_RANGE - 1);
1748 //printf("%d\n", r);
1749                         g = min_output_v + 
1750                                 g * 
1751                                 (max_output_v - min_output_v) / 
1752                                 (HISTOGRAM_RANGE - 1);
1753                         b = min_output_v + 
1754                                 b * 
1755                                 (max_output_v - min_output_v) / 
1756                                 (HISTOGRAM_RANGE - 1);
1757                         a = min_output_v + 
1758                                 a * 
1759                                 (max_output_v - min_output_v) / 
1760                                 (HISTOGRAM_RANGE - 1);
1764 // Convert to desired colormodel
1765                         switch(colormodel)
1766                         {
1767                                 case BC_RGB888:
1768                                 case BC_RGBA8888:
1769                                         plugin->lookup[0][i] = ((int)r) >> 8;
1770                                         plugin->lookup[1][i] = ((int)g) >> 8;
1771                                         plugin->lookup[2][i] = ((int)b) >> 8;
1772                                         plugin->lookup[3][i] = ((int)a) >> 8;
1773                                         break;
1774                                 default:
1775 // Can't look up yuv.
1776                                         plugin->lookup[0][i] = (int)r;
1777                                         plugin->lookup[1][i] = (int)g;
1778                                         plugin->lookup[2][i] = (int)b;
1779                                         plugin->lookup[3][i] = (int)a;
1780                                         break;
1781                         }
1782                 }
1783         }
1791 HistogramEngine::HistogramEngine(HistogramMain *plugin, 
1792         int total_clients, 
1793         int total_packages)
1794  : LoadServer(total_clients, total_packages)
1796         this->plugin = plugin;
1799 void HistogramEngine::init_packages()
1801         int total_size;
1803         switch(operation)
1804         {
1805                 case HISTOGRAM:
1806                         total_size = data->get_h();
1807                         break;
1808                 case TABULATE:
1809                         total_size = HISTOGRAM_RANGE;
1810                         break;
1811                 case APPLY:
1812                         total_size = data->get_h();
1813                         break;
1814         }
1815         int package_size = (int)((float)total_size / 
1816                         get_total_packages() + 1);
1817         int start = 0;
1818         for(int i = 0; i < get_total_packages(); i++)
1819         {
1820                 HistogramPackage *package = (HistogramPackage*)get_package(i);
1821                 package->start = start;
1822                 package->end = start + package_size;
1823                 if(package->end > total_size)
1824                         package->end = total_size;
1825                 start = package->end;
1826         }
1828 // Initialize clients here in case some don't get run.
1829         for(int i = 0; i < get_total_clients(); i++)
1830         {
1831                 HistogramUnit *unit = (HistogramUnit*)get_client(i);
1832                 for(int i = 0; i < 5; i++)
1833                         bzero(unit->accum[i], sizeof(int64_t) * HISTOGRAM_RANGE);
1834         }
1837 LoadClient* HistogramEngine::new_client()
1839         return new HistogramUnit(this, plugin);
1842 LoadPackage* HistogramEngine::new_package()
1844         return new HistogramPackage;
1847 void HistogramEngine::process_packages(int operation, VFrame *data)
1849         this->data = data;
1850         this->operation = operation;
1851         LoadServer::process_packages();