r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / plugins / histogram / histogram.C
blob57d14d17a45f39d4c902f22ee5519b26a50d1fd9
1 #include <math.h>
2 #include <stdint.h>
3 #include <string.h>
5 #include "bcdisplayinfo.h"
6 #include "bcsignals.h"
7 #include "clip.h"
8 #include "defaults.h"
9 #include "filexml.h"
10 #include "keyframe.h"
11 #include "loadbalance.h"
12 #include "max_picon_png.h"
13 #include "mid_picon_png.h"
14 #include "min_picon_png.h"
15 #include "picon_png.h"
16 #include "../libcolors/plugincolors.h"
17 #include "pluginvclient.h"
18 #include "vframe.h"
21 #include <libintl.h>
22 #define _(String) gettext(String)
23 #define gettext_noop(String) String
24 #define N_(String) gettext_noop (String)
27 class HistogramMain;
28 class HistogramEngine;
29 class HistogramWindow;
31 // modes
32 #define HISTOGRAM_RED 0
33 #define HISTOGRAM_GREEN 1
34 #define HISTOGRAM_BLUE 2
35 #define HISTOGRAM_ALPHA 3
36 #define HISTOGRAM_VALUE 4
38 // range
39 #define HISTOGRAM_RANGE 0x10000
41 #define THRESHOLD_SCALE 1000
43 class HistogramConfig
45 public:
46         HistogramConfig();
48         int equivalent(HistogramConfig &that);
49         void copy_from(HistogramConfig &that);
50         void interpolate(HistogramConfig &prev, 
51                 HistogramConfig &next, 
52                 int64_t prev_frame, 
53                 int64_t next_frame, 
54                 int64_t current_frame);
55         void reset(int do_mode);
57         int input_min[5];
58         int input_mid[5];
59         int input_max[5];
60         int output_min[5];
61         int output_max[5];
62         int automatic;
63         int mode;
64         int threshold;
69 class HistogramSlider : public BC_SubWindow
71 public:
72         HistogramSlider(HistogramMain *plugin, 
73                 HistogramWindow *gui,
74                 int x, 
75                 int y, 
76                 int w,
77                 int h,
78                 int is_input);
80         void update();
81         int button_press_event();
82         int button_release_event();
83         int cursor_motion_event();
85         int operation;
86         enum
87         {
88                 NONE,
89                 DRAG_MIN_INPUT,
90                 DRAG_MID_INPUT,
91                 DRAG_MAX_INPUT,
92                 DRAG_MIN_OUTPUT,
93                 DRAG_MAX_OUTPUT,
94         };
95         int is_input;
96         HistogramMain *plugin;
97         HistogramWindow *gui;
100 class HistogramAuto : public BC_CheckBox
102 public:
103         HistogramAuto(HistogramMain *plugin, 
104                 int x, 
105                 int y);
106         int handle_event();
107         HistogramMain *plugin;
110 class HistogramMode : public BC_Radial
112 public:
113         HistogramMode(HistogramMain *plugin, 
114                 int x, 
115                 int y,
116                 int value,
117                 char *text);
118         int handle_event();
119         HistogramMain *plugin;
120         int value;
123 class HistogramReset : public BC_GenericButton
125 public:
126         HistogramReset(HistogramMain *plugin, 
127                 int x,
128                 int y);
129         int handle_event();
130         HistogramMain *plugin;
133 class HistogramText : public BC_TumbleTextBox
135 public:
136         HistogramText(HistogramMain *plugin,
137                 HistogramWindow *gui,
138                 int x,
139                 int y,
140                 int *output);
141         int handle_event();
142         HistogramMain *plugin;
143         int *output;
146 class HistogramWindow : public BC_Window
148 public:
149         HistogramWindow(HistogramMain *plugin, int x, int y);
150         ~HistogramWindow();
152         int create_objects();
153         int close_event();
154         void update(int do_input);
155         void update_mode();
156         void update_canvas();
157         void update_input();
158         void update_output();
160         HistogramSlider *input, *output;
161         HistogramAuto *automatic;
162         HistogramMode *mode_v, *mode_r, *mode_g, *mode_b,  *mode_a;
163         HistogramText *input_min;
164         HistogramText *input_mid;
165         HistogramText *input_max;
166         HistogramText *output_min;
167         HistogramText *output_max;
168         HistogramText *threshold;
169         BC_SubWindow *canvas;
170         HistogramMain *plugin;
171         BC_Pixmap *max_picon, *mid_picon, *min_picon;
176 PLUGIN_THREAD_HEADER(HistogramMain, HistogramThread, HistogramWindow)
179 class HistogramMain : public PluginVClient
181 public:
182         HistogramMain(PluginServer *server);
183         ~HistogramMain();
185         int process_realtime(VFrame *input_ptr, VFrame *output_ptr);
186         int is_realtime();
187         int load_defaults();
188         int save_defaults();
189         void save_data(KeyFrame *keyframe);
190         void read_data(KeyFrame *keyframe);
191         void update_gui();
192         void render_gui(void *data);
193         PLUGIN_CLASS_MEMBERS(HistogramConfig, HistogramThread)
195 // Convert input to input curve
196         float calculate_curve(float input, int mode);
197 // Calculate automatic settings
198         void calculate_automatic(VFrame *data);
199 // Calculate histogram
200         void calculate_histogram(VFrame *data);
204         YUV yuv;
205         VFrame *input, *output;
206         HistogramEngine *engine;
207         int *lookup[4];
208         int64_t *accum[5];
211 class HistogramPackage : public LoadPackage
213 public:
214         HistogramPackage();
215         int start, end;
218 class HistogramUnit : public LoadClient
220 public:
221         HistogramUnit(HistogramEngine *server, HistogramMain *plugin);
222         ~HistogramUnit();
223         void process_package(LoadPackage *package);
224         HistogramEngine *server;
225         HistogramMain *plugin;
226         int64_t *accum[5];
229 class HistogramEngine : public LoadServer
231 public:
232         HistogramEngine(HistogramMain *plugin, 
233                 int total_clients, 
234                 int total_packages);
235         void process_packages(int operation, VFrame *data);
236         void init_packages();
237         LoadClient* new_client();
238         LoadPackage* new_package();
239         HistogramMain *plugin;
241         int operation;
242         enum
243         {
244                 HISTOGRAM,
245                 TABULATE,
246                 APPLY
247         };
248         VFrame *data;
269 REGISTER_PLUGIN(HistogramMain)
273 HistogramConfig::HistogramConfig()
275         reset(1);
278 void HistogramConfig::reset(int do_mode)
280         for(int i = 0; i < 5; i++)
281         {
282                 input_min[i] = 0;
283                 input_mid[i] = 0x8000;
284                 input_max[i] = 0xffff;
285                 output_min[i] = 0;
286                 output_max[i] = 0xffff;
287         }
288         if(do_mode) 
289         {
290                 mode = HISTOGRAM_VALUE;
291                 automatic = 0;
292                 threshold = 10;
293         }
296 int HistogramConfig::equivalent(HistogramConfig &that)
298         for(int i = 0; i < 5; i++)
299         {
300                 if(input_min[i] != that.input_min[i] ||
301                         input_mid[i] != that.input_mid[i] ||
302                         input_max[i] != that.input_max[i] ||
303                         output_min[i] != that.output_min[i] ||
304                         output_max[i] != that.output_max[i]) return 0;
305         }
307         if(automatic != that.automatic ||
308                 mode != that.mode ||
309                 threshold != that.threshold) return 0;
311         return 1;
314 void HistogramConfig::copy_from(HistogramConfig &that)
316         for(int i = 0; i < 5; i++)
317         {
318                 input_min[i] = that.input_min[i];
319                 input_mid[i] = that.input_mid[i];
320                 input_max[i] = that.input_max[i];
321                 output_min[i] = that.output_min[i];
322                 output_max[i] = that.output_max[i];
323         }
325         automatic = that.automatic;
326         mode = that.mode;
327         threshold = that.threshold;
330 void HistogramConfig::interpolate(HistogramConfig &prev, 
331         HistogramConfig &next, 
332         int64_t prev_frame, 
333         int64_t next_frame, 
334         int64_t current_frame)
336         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
337         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
339         for(int i = 0; i < 5; i++)
340         {
341                 input_min[i] = (int)(prev.input_min[i] * prev_scale + next.input_min[i] * next_scale);
342                 input_mid[i] = (int)(prev.input_mid[i] * prev_scale + next.input_mid[i] * next_scale);
343                 input_max[i] = (int)(prev.input_max[i] * prev_scale + next.input_max[i] * next_scale);
344                 output_min[i] = (int)(prev.output_min[i] * prev_scale + next.output_min[i] * next_scale);
345                 output_max[i] = (int)(prev.output_max[i] * prev_scale + next.output_max[i] * next_scale);
346         }
347         threshold = (int)(prev.threshold * prev_scale + next.threshold * next_scale);
348         automatic = prev.automatic;
349         mode = prev.mode;
358 PLUGIN_THREAD_OBJECT(HistogramMain, HistogramThread, HistogramWindow)
362 HistogramWindow::HistogramWindow(HistogramMain *plugin, int x, int y)
363  : BC_Window(plugin->gui_string, 
364         x,
365         y,
366         440, 
367         480, 
368         440, 
369         480, 
370         0, 
371         1)
373         this->plugin = plugin; 
376 HistogramWindow::~HistogramWindow()
380 static VFrame max_picon_image(max_picon_png);
381 static VFrame mid_picon_image(mid_picon_png);
382 static VFrame min_picon_image(min_picon_png);
384 int HistogramWindow::create_objects()
386         int x = 10, y = 10, x1 = 10;
387         int subscript = plugin->config.mode;
389         max_picon = new BC_Pixmap(this, &max_picon_image);
390         mid_picon = new BC_Pixmap(this, &mid_picon_image);
391         min_picon = new BC_Pixmap(this, &min_picon_image);
392         add_subwindow(mode_v = new HistogramMode(plugin, 
393                 x, 
394                 y,
395                 HISTOGRAM_VALUE,
396                 _("Value")));
397         x += 70;
398         add_subwindow(mode_r = new HistogramMode(plugin, 
399                 x, 
400                 y,
401                 HISTOGRAM_RED,
402                 _("Red")));
403         x += 70;
404         add_subwindow(mode_g = new HistogramMode(plugin, 
405                 x, 
406                 y,
407                 HISTOGRAM_GREEN,
408                 _("Green")));
409         x += 70;
410         add_subwindow(mode_b = new HistogramMode(plugin, 
411                 x, 
412                 y,
413                 HISTOGRAM_BLUE,
414                 _("Blue")));
415         x += 70;
416         add_subwindow(mode_a = new HistogramMode(plugin, 
417                 x, 
418                 y,
419                 HISTOGRAM_ALPHA,
420                 _("Alpha")));
422         x = x1;
423         y += 30;
424         add_subwindow(new BC_Title(x, y, _("Input min:")));
425         x += 80;
426         input_min = new HistogramText(plugin,
427                 this,
428                 x,
429                 y,
430                 &plugin->config.input_min[subscript]);
431         input_min->create_objects();
432         x += 90;
433         add_subwindow(new BC_Title(x, y, _("Mid:")));
434         x += 40;
435         input_mid = new HistogramText(plugin,
436                 this,
437                 x,
438                 y,
439                 &plugin->config.input_mid[subscript]);
440         input_mid->create_objects();
441         input_mid->update((int64_t)plugin->config.input_mid[subscript]);
442         x += 90;
443         add_subwindow(new BC_Title(x, y, _("Max:")));
444         x += 40;
445         input_max = new HistogramText(plugin,
446                 this,
447                 x,
448                 y,
449                 &plugin->config.input_max[subscript]);
450         input_max->create_objects();
452         x = x1;
453         y += 30;
454         add_subwindow(canvas = new BC_SubWindow(x, 
455                 y, 
456                 get_w() - x - x, 
457                 get_h() - y - 150,
458                 0xffffff));
460         y += canvas->get_h() + 10;
461         add_subwindow(input = new HistogramSlider(plugin, 
462                 this,
463                 x, 
464                 y, 
465                 get_w() - 20,
466                 30,
467                 1));
468         input->update();
470         y += input->get_h() + 10;
471         add_subwindow(new BC_Title(x, y, _("Output min:")));
472         x += 90;
473         output_min = new HistogramText(plugin,
474                 this,
475                 x,
476                 y,
477                 &plugin->config.output_min[subscript]);
478         output_min->create_objects();
479         x += 90;
480         add_subwindow(new BC_Title(x, y, _("Max:")));
481         x += 40;
482         output_max = new HistogramText(plugin,
483                 this,
484                 x,
485                 y,
486                 &plugin->config.output_max[subscript]);
487         output_max->create_objects();
489         x = x1;
490         y += 30;
494         add_subwindow(output = new HistogramSlider(plugin, 
495                 this,
496                 x, 
497                 y, 
498                 get_w() - 20,
499                 30,
500                 0));
501         output->update();
502         y += 40;
505         add_subwindow(automatic = new HistogramAuto(plugin, 
506                 x, 
507                 y));
509         x += 120;
510         add_subwindow(new HistogramReset(plugin, 
511                 x, 
512                 y));
513         x += 100;
514         add_subwindow(new BC_Title(x, y, _("Threshold:")));
515         x += 100;
516         threshold = new HistogramText(plugin,
517                 this,
518                 x,
519                 y,
520                 &plugin->config.threshold);
521         threshold->create_objects();
523         show_window();
524         flush();
525         return 0;
528 WINDOW_CLOSE_EVENT(HistogramWindow)
530 void HistogramWindow::update(int do_input)
532         automatic->update(plugin->config.automatic);
533         threshold->update((int64_t)plugin->config.threshold);
534         update_mode();
536         if(do_input) update_input();
537         update_output();
540 void HistogramWindow::update_input()
542         int subscript = plugin->config.mode;
543         input->update();
544         input_min->update((int64_t)plugin->config.input_min[subscript]);
545         input_mid->update((int64_t)plugin->config.input_mid[subscript]);
546         input_max->update((int64_t)plugin->config.input_max[subscript]);
549 void HistogramWindow::update_output()
551         int subscript = plugin->config.mode;
552         output->update();
553         output_min->update((int64_t)plugin->config.output_min[subscript]);
554         output_max->update((int64_t)plugin->config.output_max[subscript]);
557 void HistogramWindow::update_mode()
559         mode_v->update(plugin->config.mode == HISTOGRAM_VALUE ? 1 : 0);
560         mode_r->update(plugin->config.mode == HISTOGRAM_RED ? 1 : 0);
561         mode_g->update(plugin->config.mode == HISTOGRAM_GREEN ? 1 : 0);
562         mode_b->update(plugin->config.mode == HISTOGRAM_BLUE ? 1 : 0);
563         mode_a->update(plugin->config.mode == HISTOGRAM_ALPHA ? 1 : 0);
564         input_min->output = &plugin->config.input_min[plugin->config.mode];
565         input_mid->output = &plugin->config.input_mid[plugin->config.mode];
566         input_max->output = &plugin->config.input_max[plugin->config.mode];
567         output_min->output = &plugin->config.output_min[plugin->config.mode];
568         output_max->output = &plugin->config.output_max[plugin->config.mode];
571 void HistogramWindow::update_canvas()
573         int64_t *accum = plugin->accum[plugin->config.mode];
574         int canvas_w = canvas->get_w();
575         int canvas_h = canvas->get_h();
576         int accum_per_canvas_i = HISTOGRAM_RANGE / canvas_w + 1;
577         float accum_per_canvas_f = (float)HISTOGRAM_RANGE / canvas_w;
578         int normalize = 0;
579         int max = 0;
580         for(int i = 0; i < HISTOGRAM_RANGE; i++)
581         {
582                 if(accum[i] > normalize) normalize = accum[i];
583         }
586         if(normalize)
587         {
588                 for(int i = 0; i < canvas_w; i++)
589                 {
590                         int accum_start = (int)(accum_per_canvas_f * i);
591                         int accum_end = accum_start + accum_per_canvas_i;
592                         max = 0;
593                         for(int j = accum_start; j < accum_end; j++)
594                         {
595                                 max = MAX(accum[j], max);
596                         }
597 //printf("HistogramWindow::update_canvas 1 %d %d\n", i, max);
599 //                      max = max * canvas_h / normalize;
600                         max = (int)(log(max) / log(normalize) * canvas_h);
603                         canvas->set_color(0xffffff);
604                         canvas->draw_line(i, 0, i, canvas_h - max);
605                         canvas->set_color(0x000000);
606                         canvas->draw_line(i, canvas_h - max, i, canvas_h);
607                 }
608         }
609         else
610         {
611                 canvas->set_color(0xffffff);
612                 canvas->draw_box(0, 0, canvas_w, canvas_h);
613         }
615         canvas->set_color(0x00ff00);
616         int y1;
617         for(int i = 0; i < canvas_w; i++)
618         {
619                 int y2 = canvas_h - (int)(plugin->calculate_curve((float)i / canvas_w * (HISTOGRAM_RANGE - 1), 
620                         plugin->config.mode) * canvas_h / (HISTOGRAM_RANGE - 1));
621                 if(i > 0)
622                 {
623                         canvas->draw_line(i - 1, y1, i, y2);
624                 }
625                 y1 = y2;
626         }
628         canvas->flash();
638 HistogramReset::HistogramReset(HistogramMain *plugin, 
639         int x,
640         int y)
641  : BC_GenericButton(x, y, _("Reset"))
643         this->plugin = plugin;
645 int HistogramReset::handle_event()
647         plugin->config.reset(0);
648         plugin->thread->window->update(1);
649         plugin->send_configure_change();
650         return 1;
661 HistogramSlider::HistogramSlider(HistogramMain *plugin, 
662         HistogramWindow *gui,
663         int x, 
664         int y, 
665         int w,
666         int h,
667         int is_input)
668  : BC_SubWindow(x, y, w, h)
670         this->plugin = plugin;
671         this->gui = gui;
672         this->is_input = is_input;
673         operation = NONE;
676 int HistogramSlider::button_press_event()
678         if(is_event_win() && cursor_inside())
679         {
680                 int subscript = plugin->config.mode;
681                 int min;
682                 int max;
683                 int w = get_w();
684                 int h = get_h();
685                 int half_h = get_h() / 2;
687                 if(is_input)
688                 {
689                         int x1 = (int)(plugin->config.input_mid[subscript] * w / 0xffff) - 
690                                 gui->mid_picon->get_w() / 2;
691                         int x2 = x1 + gui->mid_picon->get_w();
692                         if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
693                                 get_cursor_y() >= half_h && get_cursor_y() < h)
694                         {
695                                 operation = DRAG_MID_INPUT;
696                         }
697                 }
699                 if(operation == NONE)
700                 {
701                         if(is_input)
702                         {
703                                 int x1 = (int)(plugin->config.input_min[subscript] * w / 0xffff) - 
704                                         gui->mid_picon->get_w() / 2;
705                                 int x2 = x1 + gui->mid_picon->get_w();
706                                 if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
707                                         get_cursor_y() >= half_h && get_cursor_y() < h)
708                                 {
709                                         operation = DRAG_MIN_INPUT;
710                                 }
711                         }
712                         else
713                         {
714                                 int x1 = (int)(plugin->config.output_min[subscript] * w / 0xffff) - 
715                                         gui->mid_picon->get_w() / 2;
716                                 int x2 = x1 + gui->mid_picon->get_w();
717                                 if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
718                                         get_cursor_y() >= half_h && get_cursor_y() < h)
719                                 {
720                                         operation = DRAG_MIN_OUTPUT;
721                                 }
722                         }
723                 }
725                 if(operation == NONE)
726                 {
727                         if(is_input)
728                         {
729                                 int x1 = (int)(plugin->config.input_max[subscript] * w / 0xffff) - 
730                                         gui->mid_picon->get_w() / 2;
731                                 int x2 = x1 + gui->mid_picon->get_w();
732                                 if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
733                                         get_cursor_y() >= half_h && get_cursor_y() < h)
734                                 {
735                                         operation = DRAG_MAX_INPUT;
736                                 }
737                         }
738                         else
739                         {
740                                 int x1 = (int)(plugin->config.output_max[subscript] * w / 0xffff) - 
741                                         gui->mid_picon->get_w() / 2;
742                                 int x2 = x1 + gui->mid_picon->get_w();
743                                 if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
744                                         get_cursor_y() >= half_h && get_cursor_y() < h)
745                                 {
746                                         operation = DRAG_MAX_OUTPUT;
747                                 }
748                         }
749                 }
750                 return 1;
751         }
752         return 0;
755 int HistogramSlider::button_release_event()
757         if(operation != NONE)
758         {
759                 operation = NONE;
760                 return 1;
761         }
762         return 0;
765 int HistogramSlider::cursor_motion_event()
767 //printf("HistogramSlider::cursor_motion_event 1\n");
768         if(operation != NONE)
769         {
770                 float value = (float)get_cursor_x() * 0xffff / get_w();
771                 CLAMP(value, 0, 0xffff);
772                 int subscript = plugin->config.mode;
773                 float input_min = plugin->config.input_min[subscript];
774                 float input_max = plugin->config.input_max[subscript];
775                 float input_mid = plugin->config.input_mid[subscript];
776                 float input_mid_fraction = (input_mid - input_min) / (input_max - input_min);
778                 switch(operation)
779                 {
780                         case DRAG_MIN_INPUT:
781                                 input_min = MIN(input_max, value);
782                                 plugin->config.input_min[subscript] = (int)input_min;
783                                 input_mid = input_min + (input_max - input_min) * input_mid_fraction;
784                                 break;
785                         case DRAG_MID_INPUT:
786                                 CLAMP(value, input_min, input_max);
787                                 input_mid = (int)value;
788                                 break;
789                         case DRAG_MAX_INPUT:
790                                 input_max = MAX(input_mid, value);
791                                 input_mid = input_min + (input_max - input_min) * input_mid_fraction;
792                                 break;
793                         case DRAG_MIN_OUTPUT:
794                                 value = MIN(plugin->config.output_max[subscript], value);
795                                 plugin->config.output_min[subscript] = (int)value;
796                                 break;
797                         case DRAG_MAX_OUTPUT:
798                                 value = MAX(plugin->config.output_min[subscript], value);
799                                 plugin->config.output_max[subscript] = (int)value;
800                                 break;
801                 }
802         
803                 if(operation == DRAG_MIN_INPUT ||
804                         operation == DRAG_MID_INPUT ||
805                         operation == DRAG_MAX_INPUT)
806                 {
807                         plugin->config.input_mid[subscript] = (int)input_mid;
808                         plugin->config.input_min[subscript] = (int)input_min;
809                         plugin->config.input_max[subscript] = (int)input_max;
810                         gui->update_input();
811                 }
812                 else
813                 {
814                         gui->update_output();
815                 }
817                 gui->unlock_window();
818                 plugin->send_configure_change();
819 //printf("HistogramSlider::cursor_motion_event 2\n");
820                 gui->lock_window();
821 //printf("HistogramSlider::cursor_motion_event 3\n");
822                 return 1;
823         }
824         return 0;
827 void HistogramSlider::update()
829         int w = get_w();
830         int h = get_h();
831         int half_h = get_h() / 2;
832         int quarter_h = get_h() / 4;
833         int mode = plugin->config.mode;
834         int r = 0xff;
835         int g = 0xff;
836         int b = 0xff;
837         int subscript = plugin->config.mode;
839         clear_box(0, 0, w, h);
841         switch(mode)
842         {
843                 case HISTOGRAM_RED:
844                         g = b = 0x00;
845                         break;
846                 case HISTOGRAM_GREEN:
847                         r = b = 0x00;
848                         break;
849                 case HISTOGRAM_BLUE:
850                         r = g = 0x00;
851                         break;
852         }
854         for(int i = 0; i < w; i++)
855         {
856                 int color = (int)(i * 0xff / w);
857                 set_color(((r * color / 0xff) << 16) | 
858                         ((g * color / 0xff) << 8) | 
859                         (b * color / 0xff));
861                 if(is_input)
862                 {
863                         draw_line(i, quarter_h, i, half_h);
864                         color = (int)plugin->calculate_curve(i * 0xffff / w, 
865                                 subscript);
866                         set_color(((r * color / 0xffff) << 16) | 
867                                 ((g * color / 0xffff) << 8) | 
868                                 (b * color / 0xffff));
869                         draw_line(i, 0, i, quarter_h);
870                 }
871                 else
872                         draw_line(i, 0, i, half_h);
874         }
876         int min;
877         int max;
878         if(is_input)
879         {
880                 
881                 draw_pixmap(gui->mid_picon,
882                         (int)(plugin->config.input_mid[subscript] * w / 0xffff) - 
883                                 gui->mid_picon->get_w() / 2,
884                         half_h + 1);
885                 min = plugin->config.input_min[subscript];
886                 max = plugin->config.input_max[subscript];
887         }
888         else
889         {
890                 min = plugin->config.output_min[subscript];
891                 max = plugin->config.output_max[subscript];
892         }
894         draw_pixmap(gui->min_picon,
895                 min * w / 0xffff - gui->min_picon->get_w() / 2,
896                 half_h + 1);
897         draw_pixmap(gui->max_picon,
898                 max * w / 0xffff - gui->max_picon->get_w() / 2,
899                 half_h + 1);
901 // printf("HistogramSlider::update %d %d\n", min, max);
902         flash();
903         flush();
914 HistogramAuto::HistogramAuto(HistogramMain *plugin, 
915         int x, 
916         int y)
917  : BC_CheckBox(x, y, plugin->config.automatic, _("Automatic"))
919         this->plugin = plugin;
922 int HistogramAuto::handle_event()
924         plugin->config.automatic = get_value();
925         plugin->send_configure_change();
926         return 1;
932 HistogramMode::HistogramMode(HistogramMain *plugin, 
933         int x, 
934         int y,
935         int value,
936         char *text)
937  : BC_Radial(x, y, plugin->config.mode == value, text)
939         this->plugin = plugin;
940         this->value = value;
942 int HistogramMode::handle_event()
944         plugin->config.mode = value;
945         plugin->thread->window->update_mode();
946         plugin->thread->window->input->update();
947         plugin->thread->window->output->update();
948         plugin->send_configure_change();
949         return 1;
960 HistogramText::HistogramText(HistogramMain *plugin,
961         HistogramWindow *gui,
962         int x,
963         int y,
964         int *output)
965  : BC_TumbleTextBox(gui, 
966                 (int64_t)*output,
967                 (int64_t)0,
968                 (int64_t)0xff,
969                 x, 
970                 y, 
971                 60)
973         this->plugin = plugin;
974         this->output = output;
978 int HistogramText::handle_event()
980         if(output)
981         {
982                 *output = atol(get_text());
983         }
984         plugin->thread->window->input->update();
985         plugin->thread->window->output->update();
986         plugin->send_configure_change();
987         return 1;
1011 HistogramMain::HistogramMain(PluginServer *server)
1012  : PluginVClient(server)
1014         PLUGIN_CONSTRUCTOR_MACRO
1015         engine = 0;
1016         lookup[0] = lookup[1] = lookup[2] = lookup[3] = 0;
1017         accum[0] = accum[1] = accum[2] = accum[3] = accum[3] = 0;
1020 HistogramMain::~HistogramMain()
1022         PLUGIN_DESTRUCTOR_MACRO
1023         if(lookup[0]) delete [] lookup[0];
1024         if(lookup[1]) delete [] lookup[1];
1025         if(lookup[2]) delete [] lookup[2];
1026         if(lookup[3]) delete [] lookup[3];
1027         if(accum[0]) delete [] accum[0];
1028         if(accum[1]) delete [] accum[1];
1029         if(accum[2]) delete [] accum[2];
1030         if(accum[3]) delete [] accum[3];
1031         if(accum[4]) delete [] accum[4];
1032         if(engine) delete engine;
1035 char* HistogramMain::plugin_title() { return _("Histogram"); }
1036 int HistogramMain::is_realtime() { return 1; }
1039 NEW_PICON_MACRO(HistogramMain)
1041 SHOW_GUI_MACRO(HistogramMain, HistogramThread)
1043 SET_STRING_MACRO(HistogramMain)
1045 RAISE_WINDOW_MACRO(HistogramMain)
1047 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
1049 void HistogramMain::render_gui(void *data)
1052         if(thread)
1053         {
1054 //printf("HistogramMain::render_gui 1\n");
1055                 thread->window->lock_window();
1056 //printf("HistogramMain::render_gui 2\n");
1057                 calculate_histogram((VFrame*)data);
1058 //printf("HistogramMain::render_gui 3\n");
1059                 if(config.automatic)
1060                 {
1061                         calculate_automatic((VFrame*)data);
1062                 }
1063 //printf("HistogramMain::render_gui 3\n");
1065                 thread->window->update_canvas();
1066 //printf("HistogramMain::render_gui 3\n");
1067                 if(config.automatic)
1068                 {
1069                         thread->window->update_input();
1070                 }
1071 //printf("HistogramMain::render_gui 3\n");
1072                 thread->window->unlock_window();
1073         }
1074 //printf("HistogramMain::render_gui 4\n");
1077 void HistogramMain::update_gui()
1079         if(thread)
1080         {
1081                 thread->window->lock_window();
1082                 int reconfigure = load_configuration();
1083                 if(reconfigure) 
1084                 {
1085                         thread->window->update(0);
1086                         if(!config.automatic)
1087                         {
1088                                 thread->window->update_input();
1089                         }
1090                 }
1091                 thread->window->unlock_window();
1092         }
1096 int HistogramMain::load_defaults()
1098         char directory[BCTEXTLEN], string[BCTEXTLEN];
1099 // set the default directory
1100         sprintf(directory, "%shistogram.rc", BCASTDIR);
1102 // load the defaults
1103         defaults = new Defaults(directory);
1104         defaults->load();
1106         for(int i = 0; i < 5; i++)
1107         {
1108                 sprintf(string, "INPUT_MIN_%d", i);
1109                 config.input_min[i] = defaults->get(string, config.input_min[i]);
1110                 sprintf(string, "INPUT_MID_%d", i);
1111                 config.input_mid[i] = defaults->get(string, config.input_mid[i]);
1112                 sprintf(string, "INPUT_MAX_%d", i);
1113                 config.input_max[i] = defaults->get(string, config.input_max[i]);
1114                 sprintf(string, "OUTPUT_MIN_%d", i);
1115                 config.output_min[i] = defaults->get(string, config.output_min[i]);
1116                 sprintf(string, "OUTPUT_MAX_%d", i);
1117                 config.output_max[i] = defaults->get(string, config.output_max[i]);
1118 //printf("HistogramMain::load_defaults %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
1119         }
1120         config.automatic = defaults->get("AUTOMATIC", config.automatic);
1121         config.mode = defaults->get("MODE", config.mode);
1122         config.threshold = defaults->get("THRESHOLD", config.threshold);
1123         return 0;
1127 int HistogramMain::save_defaults()
1129         char string[BCTEXTLEN];
1130 //printf("HistogramMain::save_defaults 1 %p\n", defaults);
1131         for(int i = 0; i < 5; i++)
1132         {
1133 //printf("HistogramMain::save_defaults 1 %d\n", i);
1134                 sprintf(string, "INPUT_MIN_%d", i);
1135                 defaults->update(string, config.input_min[i]);
1136 //printf("HistogramMain::save_defaults 1 %d\n", i);
1137                 sprintf(string, "INPUT_MID_%d", i);
1138                 defaults->update(string, config.input_mid[i]);
1139 //printf("HistogramMain::save_defaults 1 %d\n", i);
1140                 sprintf(string, "INPUT_MAX_%d", i);
1141 //printf("HistogramMain::save_defaults 1 %d\n", config.input_max[i]);
1142                 defaults->update(string, config.input_max[i]);
1143 //printf("HistogramMain::save_defaults 1 %d\n", i);
1144                 sprintf(string, "OUTPUT_MIN_%d", i);
1145                 defaults->update(string, config.output_min[i]);
1146 //printf("HistogramMain::save_defaults 1 %d\n", i);
1147                 sprintf(string, "OUTPUT_MAX_%d", i);
1148                 defaults->update(string, config.output_max[i]);
1149 //printf("HistogramMain::save_defaults %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
1150         }
1151 //printf("HistogramMain::save_defaults 3\n");
1152         defaults->update("AUTOMATIC", config.automatic);
1153 //printf("HistogramMain::save_defaults 4\n");
1154         defaults->update("MODE", config.mode);
1155         defaults->update("THRESHOLD", config.threshold);
1156 //printf("HistogramMain::save_defaults 5\n");
1157         defaults->save();
1158 //printf("HistogramMain::save_defaults 6\n");
1159         return 0;
1164 void HistogramMain::save_data(KeyFrame *keyframe)
1166         FileXML output;
1168 // cause data to be stored directly in text
1169         output.set_shared_string(keyframe->data, MESSAGESIZE);
1170         output.tag.set_title("HISTOGRAM");
1172         char string[BCTEXTLEN];
1173         for(int i = 0; i < 5; i++)
1174         {
1175                 sprintf(string, "INPUT_MIN_%d", i);
1176                 output.tag.set_property(string, config.input_min[i]);
1177                 sprintf(string, "INPUT_MID_%d", i);
1178                 output.tag.set_property(string, config.input_mid[i]);
1179                 sprintf(string, "INPUT_MAX_%d", i);
1180                 output.tag.set_property(string, config.input_max[i]);
1181                 sprintf(string, "OUTPUT_MIN_%d", i);
1182                 output.tag.set_property(string, config.output_min[i]);
1183                 sprintf(string, "OUTPUT_MAX_%d", i);
1184                 output.tag.set_property(string, config.output_max[i]);
1185 //printf("HistogramMain::save_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
1186         }
1187         output.tag.set_property("AUTOMATIC", config.automatic);
1188         output.tag.set_property("MODE", config.mode);
1189         output.tag.set_property("THRESHOLD", config.threshold);
1190         output.append_tag();
1191         output.terminate_string();
1194 void HistogramMain::read_data(KeyFrame *keyframe)
1196         FileXML input;
1198         input.set_shared_string(keyframe->data, strlen(keyframe->data));
1200         int result = 0;
1202         while(!result)
1203         {
1204                 result = input.read_tag();
1206                 if(!result)
1207                 {
1208                         if(input.tag.title_is("HISTOGRAM"))
1209                         {
1210                                 char string[BCTEXTLEN];
1211                                 for(int i = 0; i < 5; i++)
1212                                 {
1213                                         sprintf(string, "INPUT_MIN_%d", i);
1214                                         config.input_min[i] = input.tag.get_property(string, config.input_min[i]);
1215                                         sprintf(string, "INPUT_MID_%d", i);
1216                                         config.input_mid[i] = input.tag.get_property(string, config.input_mid[i]);
1217                                         sprintf(string, "INPUT_MAX_%d", i);
1218                                         config.input_max[i] = input.tag.get_property(string, config.input_max[i]);
1219                                         sprintf(string, "OUTPUT_MIN_%d", i);
1220                                         config.output_min[i] = input.tag.get_property(string, config.output_min[i]);
1221                                         sprintf(string, "OUTPUT_MAX_%d", i);
1222                                         config.output_max[i] = input.tag.get_property(string, config.output_max[i]);
1223 //printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
1224                                 }
1225                                 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
1226                                 config.mode = input.tag.get_property("MODE", config.mode);
1227                                 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
1228                         }
1229                 }
1230         }
1233 float HistogramMain::calculate_curve(float input, int subscript)
1235         float y1, y2, y3, y4;
1236         float min = (float)config.input_min[subscript];
1237         float max = (float)config.input_max[subscript];
1238         float mid = (float)config.input_mid[subscript];
1239         float half = (float)HISTOGRAM_RANGE / 2;
1240         float output, output_perfect;
1241         float control = 1.0 / M_PI;
1242         float output_linear;
1244 // Below minimum
1245         if(input < min) return 0;
1247 // Above maximum
1248         if(input >= max) return HISTOGRAM_RANGE - 1;
1250         float slope1 = half / (mid - min);
1251         float slope2 = half / (max - mid);
1252         float min_slope = MIN(slope1, slope2);
1254 // value of 45` diagonal with midpoint
1255         output_perfect = half + min_slope * (input - mid);
1256 // Left hand side
1257         if(input < mid)
1258         {
1259 // Fraction of perfect diagonal to use
1260                 float mid_fraction = (input - min) / (mid - min);
1261 // value of line connecting min to mid
1262                 output_linear = mid_fraction * half;
1263 // Blend perfect diagonal with linear
1264                 output = output_linear * (1.0 - mid_fraction) + output_perfect * mid_fraction;
1265         }
1266         else
1267         {
1268 // Fraction of perfect diagonal to use
1269                 float mid_fraction = (max - input) / (max - mid);
1270 // value of line connecting max to mid
1271                 output_linear = half + (1.0 - mid_fraction) * half;
1272 // Blend perfect diagonal with linear
1273                 output = output_linear * (1.0 - mid_fraction) + output_perfect * mid_fraction;
1274         }
1282 // printf("HistogramMain::calculate_curve 1 %.0f %.0f %.0f %.0f %.0f\n",
1283 // output, 
1284 // input,
1285 // min,
1286 // mid,
1287 // max);
1288         return output;
1291 void HistogramMain::calculate_histogram(VFrame *data)
1293         if(!engine) engine = new HistogramEngine(this,
1294                 get_project_smp() + 1,
1295                 get_project_smp() + 1);
1297         if(!accum[0])
1298         {
1299                 for(int i = 0; i < 5; i++)
1300                         accum[i] = new int64_t[HISTOGRAM_RANGE];
1301         }
1303         engine->process_packages(HistogramEngine::HISTOGRAM, data);
1305         for(int i = 0; i < engine->get_total_clients(); i++)
1306         {
1307                 HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
1308                 if(i == 0)
1309                 {
1310                         for(int j = 0; j < 5; j++)
1311                                 memcpy(accum[j], unit->accum[j], sizeof(int64_t) * HISTOGRAM_RANGE);
1312                 }
1313                 else
1314                 {
1315                         for(int j = 0; j < 5; j++)
1316                         {
1317                                 int64_t *out = accum[j];
1318                                 int64_t *in = unit->accum[j];
1319                                 for(int k = 0; k < HISTOGRAM_RANGE; k++)
1320                                         out[k] += in[k];
1321                         }
1322                 }
1323         }
1325 // Remove top and bottom from calculations.  Doesn't work in high
1326 // precision colormodels.
1327         for(int i = 0; i < 5; i++)
1328         {
1329                 accum[i][0] = 0;
1330                 accum[i][HISTOGRAM_RANGE - 1] = 0;
1331         }
1335 void HistogramMain::calculate_automatic(VFrame *data)
1337         calculate_histogram(data);
1340         for(int i = 0; i < 3; i++)
1341         {
1342                 int64_t *accum = this->accum[i];
1343                 int max = 0;
1345                 for(int j = 0; j < HISTOGRAM_RANGE; j++)
1346                 {
1347                         max = MAX(accum[j], max);
1348                 }
1350                 int threshold = config.threshold * max / THRESHOLD_SCALE;
1353 // Minimums
1354                 config.input_min[i] = 0;
1355                 for(int j = 0; j < HISTOGRAM_RANGE; j++)
1356                 {
1357                         if(accum[j] > threshold)
1358                         {
1359                                 config.input_min[i] = j;
1360                                 break;
1361                         }
1362                 }
1365 // Maximums
1366                 config.input_max[i] = 0xffff;
1367                 for(int j = HISTOGRAM_RANGE - 1; j >= 0; j--)
1368                 {
1369                         if(accum[j] > threshold)
1370                         {
1371                                 config.input_max[i] = j;
1372                                 break;
1373                         }
1374                 }
1376                 config.input_mid[i] = (config.input_min[i] + config.input_max[i]) / 2;
1377         }
1385 int HistogramMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
1387 //printf("HistogramMain::process_realtime 1\n");
1388 TRON("HistogramMain::process_realtime");
1389 //printf("HistogramMain::process_realtime 1\n");
1390         int need_reconfigure = load_configuration();
1393         if(!engine) engine = new HistogramEngine(this,
1394                 get_project_smp() + 1,
1395                 get_project_smp() + 1);
1396         this->input = input_ptr;
1397         this->output = output_ptr;
1399 //printf("HistogramMain::process_realtime 1\n");
1400         send_render_gui(input_ptr);
1401 //printf("HistogramMain::process_realtime 1\n");
1403         if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
1404         {
1405                 output_ptr->copy_from(input_ptr);
1406         }
1407 //printf("HistogramMain::process_realtime 1\n");
1409 // Generate tables here.  The same table is used by many packages to render
1410 // each horizontal stripe.  Need to cover the entire output range in  each
1411 // table to avoid green borders
1412         if(need_reconfigure || !lookup[0] || config.automatic)
1413         {
1414                 if(!lookup[0])
1415                         for(int i = 0; i < 4; i++)
1416                                 lookup[i] = new int[HISTOGRAM_RANGE];
1418 // Calculate new curves
1419                 if(config.automatic)
1420                 {
1421                         calculate_automatic(input);
1422                 }
1424                 engine->process_packages(HistogramEngine::TABULATE, input);
1428 // Convert 16 bit lookup table to 8 bits
1429                 switch(input->get_color_model())
1430                 {
1431                         case BC_RGB888:
1432                         case BC_RGBA8888:
1433                                 for(int i = 0; i < 0x100; i++)
1434                                 {
1435                                         int subscript = (i << 8) | i;
1436                                         lookup[0][i] = lookup[0][subscript];
1437                                         lookup[1][i] = lookup[1][subscript];
1438                                         lookup[2][i] = lookup[2][subscript];
1439                                         lookup[3][i] = lookup[3][subscript];
1440                                 }
1441                                 break;
1442                 }
1443         }
1444 //printf("HistogramMain::process_realtime 1\n");
1449 // Apply histogram
1450         engine->process_packages(HistogramEngine::APPLY, input);
1452 //printf("HistogramMain::process_realtime 100\n");
1455 TROFF("HistogramMain::process_realtime");
1457         return 0;
1465 HistogramPackage::HistogramPackage()
1466  : LoadPackage()
1473 HistogramUnit::HistogramUnit(HistogramEngine *server, 
1474         HistogramMain *plugin)
1475  : LoadClient(server)
1477         this->plugin = plugin;
1478         this->server = server;
1479         bzero(accum, sizeof(accum));
1482 HistogramUnit::~HistogramUnit()
1484         if(accum[0]) delete [] accum[0];
1485         if(accum[1]) delete [] accum[1];
1486         if(accum[2]) delete [] accum[2];
1487         if(accum[3]) delete [] accum[3];
1488         if(accum[4]) delete [] accum[4];
1491 void HistogramUnit::process_package(LoadPackage *package)
1493         HistogramPackage *pkg = (HistogramPackage*)package;
1495         if(server->operation == HistogramEngine::HISTOGRAM)
1496         {
1498 #define HISTOGRAM_HEAD(type) \
1499 { \
1500         for(int i = pkg->start; i < pkg->end; i++) \
1501         { \
1502                 type *row = (type*)data->get_rows()[i]; \
1503                 for(int j = 0; j < w; j++) \
1504                 {
1506 #define HISTOGRAM_TAIL(components) \
1507                         v = MAX(r, g); \
1508                         v = MAX(v, b); \
1509                         accum_r[r]++; \
1510                         accum_g[g]++; \
1511                         accum_b[b]++; \
1512                         if(components == 4) accum_a[row[3]]++; \
1513                         accum_v[v]++; \
1514                         row += components; \
1515                 } \
1516         } \
1520                 if(!accum[0])
1521                 {
1522                         for(int i = 0; i < 5; i++)
1523                                 accum[i] = new int64_t[HISTOGRAM_RANGE];
1524                 }
1526                 for(int i = 0; i < 5; i++)
1527                         bzero(accum[i], sizeof(int64_t) * HISTOGRAM_RANGE);
1529                 VFrame *data = server->data;
1530                 int w = data->get_w();
1531                 int h = data->get_h();
1532                 int64_t *accum_r = accum[HISTOGRAM_RED];
1533                 int64_t *accum_g = accum[HISTOGRAM_GREEN];
1534                 int64_t *accum_b = accum[HISTOGRAM_BLUE];
1535                 int64_t *accum_a = accum[HISTOGRAM_ALPHA];
1536                 int64_t *accum_v = accum[HISTOGRAM_VALUE];
1537                 int r, g, b, a, y, u, v;
1539                 switch(data->get_color_model())
1540                 {
1541                         case BC_RGB888:
1542                                 HISTOGRAM_HEAD(unsigned char)
1543                                 r = (row[0] << 8) | row[0];
1544                                 g = (row[1] << 8) | row[1];
1545                                 b = (row[2] << 8) | row[2];
1546                                 HISTOGRAM_TAIL(3)
1547                                 break;
1548                         case BC_YUV888:
1549                                 HISTOGRAM_HEAD(unsigned char)
1550                                 y = (row[0] << 8) | row[0];
1551                                 u = (row[1] << 8) | row[1];
1552                                 v = (row[2] << 8) | row[2];
1553                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1554                                 HISTOGRAM_TAIL(3)
1555                                 break;
1556                         case BC_RGBA8888:
1557                                 HISTOGRAM_HEAD(unsigned char)
1558                                 r = (row[0] << 8) | row[0];
1559                                 g = (row[1] << 8) | row[1];
1560                                 b = (row[2] << 8) | row[2];
1561                                 HISTOGRAM_TAIL(4)
1562                                 break;
1563                         case BC_YUVA8888:
1564                                 HISTOGRAM_HEAD(unsigned char)
1565                                 y = (row[0] << 8) | row[0];
1566                                 u = (row[1] << 8) | row[1];
1567                                 v = (row[2] << 8) | row[2];
1568                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1569                                 HISTOGRAM_TAIL(4)
1570                                 break;
1571                         case BC_RGB161616:
1572                                 HISTOGRAM_HEAD(uint16_t)
1573                                 r = row[0];
1574                                 g = row[1];
1575                                 b = row[2];
1576                                 HISTOGRAM_TAIL(3)
1577                                 break;
1578                         case BC_YUV161616:
1579                                 HISTOGRAM_HEAD(uint16_t)
1580                                 y = row[0];
1581                                 u = row[1];
1582                                 v = row[2];
1583                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1584                                 HISTOGRAM_TAIL(3)
1585                                 break;
1586                         case BC_RGBA16161616:
1587                                 HISTOGRAM_HEAD(uint16_t)
1588                                 r = row[0];
1589                                 g = row[1];
1590                                 b = row[2];
1591                                 HISTOGRAM_TAIL(3)
1592                                 break;
1593                         case BC_YUVA16161616:
1594                                 HISTOGRAM_HEAD(uint16_t)
1595                                 y = row[0];
1596                                 u = row[1];
1597                                 v = row[2];
1598                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1599                                 HISTOGRAM_TAIL(4)
1600                                 break;
1601                 }
1602         }
1603         else
1604         if(server->operation == HistogramEngine::APPLY)
1605         {
1609 #define PROCESS(type, components) \
1610 { \
1611         for(int i = pkg->start; i < pkg->end; i++) \
1612         { \
1613                 type *row = (type*)input->get_rows()[i]; \
1614                 for(int j = 0; j < w; j++) \
1615                 { \
1616                         row[0] = lookup_r[row[0]]; \
1617                         row[1] = lookup_g[row[1]]; \
1618                         row[2] = lookup_b[row[2]]; \
1619                         if(components == 4) row[3] = lookup_a[row[3]]; \
1620                         row += components; \
1621                 } \
1622         } \
1625 #define PROCESS_YUV(type, components, max) \
1626 { \
1627         for(int i = pkg->start; i < pkg->end; i++) \
1628         { \
1629                 type *row = (type*)input->get_rows()[i]; \
1630                 for(int j = 0; j < w; j++) \
1631                 { \
1632 /* Convert to 16 bit RGB */ \
1633                         if(max == 0xff) \
1634                         { \
1635                                 y = (row[0] << 8) | row[0]; \
1636                                 u = (row[1] << 8) | row[1]; \
1637                                 v = (row[2] << 8) | row[2]; \
1638                                 if(components == 4) a = (row[3] << 8) | row[3]; \
1639                         } \
1640                         else \
1641                         { \
1642                                 y = row[0]; \
1643                                 u = row[1]; \
1644                                 v = row[2]; \
1645                                 if(components == 4) a = row[3]; \
1646                         } \
1648                         plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
1650 /* Look up in RGB domain */ \
1651                         r = lookup_r[r]; \
1652                         g = lookup_g[g]; \
1653                         b = lookup_b[b]; \
1654                         if(components == 4) a = lookup_a[a]; \
1656 /* Convert to 16 bit YUV */ \
1657                         plugin->yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
1659                         if(max == 0xff) \
1660                         { \
1661                                 row[0] = y >> 8; \
1662                                 row[1] = u >> 8; \
1663                                 row[2] = v >> 8; \
1664                                 if(components == 4) row[3] = a >> 8; \
1665                         } \
1666                         else \
1667                         { \
1668                                 row[0] = y; \
1669                                 row[1] = u; \
1670                                 row[2] = v; \
1671                                 if(components == 4) row[3] = a; \
1672                         } \
1673                         row += components; \
1674                 } \
1675         } \
1681                 VFrame *input = plugin->input;
1682                 VFrame *output = plugin->output;
1683                 int w = input->get_w();
1684                 int h = input->get_h();
1685                 int *lookup_r = plugin->lookup[0];
1686                 int *lookup_g = plugin->lookup[1];
1687                 int *lookup_b = plugin->lookup[2];
1688                 int *lookup_a = plugin->lookup[3];
1689                 int r, g, b, y, u, v, a;
1690                 switch(input->get_color_model())
1691                 {
1692                         case BC_RGB888:
1693                                 PROCESS(unsigned char, 3)
1694                                 break;
1695                         case BC_RGBA8888:
1696                                 PROCESS(unsigned char, 4)
1697                                 break;
1698                         case BC_RGB161616:
1699                                 PROCESS(uint16_t, 3)
1700                                 break;
1701                         case BC_RGBA16161616:
1702                                 PROCESS(uint16_t, 4)
1703                                 break;
1704                         case BC_YUV888:
1705                                 PROCESS_YUV(unsigned char, 3, 0xff)
1706                                 break;
1707                         case BC_YUVA8888:
1708                                 PROCESS_YUV(unsigned char, 4, 0xff)
1709                                 break;
1710                         case BC_YUV161616:
1711                                 PROCESS_YUV(uint16_t, 3, 0xffff)
1712                                 break;
1713                         case BC_YUVA16161616:
1714                                 PROCESS_YUV(uint16_t, 4, 0xffff)
1715                                 break;
1716                 }
1717         }
1718         if(server->operation == HistogramEngine::TABULATE)
1719         {
1720 // Do conversion in 16 bit YUVA
1721                 int min_output_r = plugin->config.output_min[0];
1722                 int min_output_g = plugin->config.output_min[1];
1723                 int min_output_b = plugin->config.output_min[2];
1724                 int min_output_a = plugin->config.output_min[3];
1725                 int min_output_v = plugin->config.output_min[4];
1726                 int max_output_r = plugin->config.output_max[0];
1727                 int max_output_g = plugin->config.output_max[1];
1728                 int max_output_b = plugin->config.output_max[2];
1729                 int max_output_a = plugin->config.output_max[3];
1730                 int max_output_v = plugin->config.output_max[4];
1731                 int colormodel = plugin->input->get_color_model();
1733                 for(int i = pkg->start; i < pkg->end; i++)
1734                 {
1735 // Expand input
1736                         float r = plugin->calculate_curve((float)i, HISTOGRAM_RED);
1737                         float g = plugin->calculate_curve((float)i, HISTOGRAM_GREEN);
1738                         float b = plugin->calculate_curve((float)i, HISTOGRAM_BLUE);
1739                         float a = plugin->calculate_curve((float)i, HISTOGRAM_ALPHA);
1740                         int y, u, v;
1741 // Expand value
1742                         r = plugin->calculate_curve((float)r, HISTOGRAM_VALUE);
1743                         g = plugin->calculate_curve((float)g, HISTOGRAM_VALUE);
1744                         b = plugin->calculate_curve((float)b, HISTOGRAM_VALUE);
1745 // r = i;
1746 // g = i;
1747 // b = i;
1749 // Shrink output
1750                         r = (float)min_output_r + 
1751                                 r * 
1752                                 (max_output_r - min_output_r) / 
1753                                 (HISTOGRAM_RANGE - 1);
1754                         g = min_output_g + 
1755                                 g * 
1756                                 (max_output_g - min_output_g) / 
1757                                 (HISTOGRAM_RANGE - 1);
1758                         b = min_output_b + 
1759                                 b * 
1760                                 (max_output_b - min_output_b) / 
1761                                 (HISTOGRAM_RANGE - 1);
1762                         a = min_output_a + 
1763                                 a * 
1764                                 (max_output_a - min_output_a) / 
1765                                 (HISTOGRAM_RANGE - 1);
1766 // Shrink value
1767 //printf(" 1 %d -> ", r);
1768                         r = min_output_v + 
1769                                 r * 
1770                                 (max_output_v - min_output_v) / 
1771                                 (HISTOGRAM_RANGE - 1);
1772 //printf("%d\n", r);
1773                         g = min_output_v + 
1774                                 g * 
1775                                 (max_output_v - min_output_v) / 
1776                                 (HISTOGRAM_RANGE - 1);
1777                         b = min_output_v + 
1778                                 b * 
1779                                 (max_output_v - min_output_v) / 
1780                                 (HISTOGRAM_RANGE - 1);
1781                         a = min_output_v + 
1782                                 a * 
1783                                 (max_output_v - min_output_v) / 
1784                                 (HISTOGRAM_RANGE - 1);
1788 // Convert to desired colormodel
1789                         switch(colormodel)
1790                         {
1791                                 case BC_RGB888:
1792                                 case BC_RGBA8888:
1793                                         plugin->lookup[0][i] = ((int)r) >> 8;
1794                                         plugin->lookup[1][i] = ((int)g) >> 8;
1795                                         plugin->lookup[2][i] = ((int)b) >> 8;
1796                                         plugin->lookup[3][i] = ((int)a) >> 8;
1797                                         break;
1798                                 default:
1799 // Can't look up yuv.
1800                                         plugin->lookup[0][i] = (int)r;
1801                                         plugin->lookup[1][i] = (int)g;
1802                                         plugin->lookup[2][i] = (int)b;
1803                                         plugin->lookup[3][i] = (int)a;
1804                                         break;
1805                         }
1806                 }
1807         }
1815 HistogramEngine::HistogramEngine(HistogramMain *plugin, 
1816         int total_clients, 
1817         int total_packages)
1818  : LoadServer(total_clients, total_packages)
1820         this->plugin = plugin;
1823 void HistogramEngine::init_packages()
1825         int total_size;
1827         switch(operation)
1828         {
1829                 case HISTOGRAM:
1830                         total_size = data->get_h();
1831                         break;
1832                 case TABULATE:
1833                         total_size = HISTOGRAM_RANGE;
1834                         break;
1835                 case APPLY:
1836                         total_size = data->get_h();
1837                         break;
1838         }
1839         int package_size = (int)((float)total_size / 
1840                         total_packages + 1);
1841         int start = 0;
1842         for(int i = 0; i < total_packages; i++)
1843         {
1844                 HistogramPackage *package = (HistogramPackage*)packages[i];
1845                 package->start = start;
1846                 package->end = start + package_size;
1847                 if(package->end > total_size)
1848                         package->end = total_size;
1849                 start = package->end;
1850         }
1853 LoadClient* HistogramEngine::new_client()
1855         return new HistogramUnit(this, plugin);
1858 LoadPackage* HistogramEngine::new_package()
1860         return new HistogramPackage;
1863 void HistogramEngine::process_packages(int operation, VFrame *data)
1865         this->data = data;
1866         this->operation = operation;
1867         LoadServer::process_packages();