r860: Merge 2.1:
[cinelerra_cv.git] / plugins / histogram / histogram.C
blob75cd6f52b428ee909b145c89159c32927a16d951
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 "bchash.h"
10 #include "filexml.h"
11 #include "histogram.h"
12 #include "histogramconfig.h"
13 #include "histogramwindow.h"
14 #include "keyframe.h"
15 #include "language.h"
16 #include "loadbalance.h"
17 #include "plugincolors.h"
18 #include "vframe.h"
22 class HistogramMain;
23 class HistogramEngine;
24 class HistogramWindow;
30 REGISTER_PLUGIN(HistogramMain)
43 HistogramMain::HistogramMain(PluginServer *server)
44  : PluginVClient(server)
46         PLUGIN_CONSTRUCTOR_MACRO
47         engine = 0;
48         for(int i = 0; i < HISTOGRAM_MODES; i++)
49         {
50                 lookup[i] = 0;
51                 smoothed[i] = 0;
52                 linear[i] = 0;
53                 accum[i] = 0;
54         }
55         current_point = -1;
56         mode = HISTOGRAM_VALUE;
57         dragging_point = 0;
58         input = 0;
59         output = 0;
62 HistogramMain::~HistogramMain()
64         PLUGIN_DESTRUCTOR_MACRO
65         for(int i = 0; i < HISTOGRAM_MODES;i++)
66         {
67                 delete [] lookup[i];
68                 delete [] smoothed[i];
69                 delete [] linear[i];
70                 delete [] accum[i];
71         }
72         delete engine;
75 char* HistogramMain::plugin_title() { return N_("Histogram"); }
76 int HistogramMain::is_realtime() { return 1; }
79 #include "picon_png.h"
80 NEW_PICON_MACRO(HistogramMain)
82 SHOW_GUI_MACRO(HistogramMain, HistogramThread)
84 SET_STRING_MACRO(HistogramMain)
86 RAISE_WINDOW_MACRO(HistogramMain)
88 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
90 void HistogramMain::render_gui(void *data)
92         if(thread)
93         {
94                 calculate_histogram((VFrame*)data);
96                 if(config.automatic)
97                 {
98 SET_TRACE
99                         calculate_automatic((VFrame*)data);
101                 }
103 SET_TRACE
104                 thread->window->lock_window("HistogramMain::render_gui");
105                 thread->window->update_canvas();
106                 if(config.automatic)
107                 {
108                         thread->window->update_input();
109                 }
110                 thread->window->unlock_window();
111 SET_TRACE
112         }
115 void HistogramMain::update_gui()
117         if(thread)
118         {
119                 thread->window->lock_window("HistogramMain::update_gui");
120                 int reconfigure = load_configuration();
121                 if(reconfigure) 
122                 {
123                         thread->window->update(0);
124                         if(!config.automatic)
125                         {
126                                 thread->window->update_input();
127                         }
128                 }
129                 thread->window->unlock_window();
130         }
134 int HistogramMain::load_defaults()
136         char directory[BCTEXTLEN], string[BCTEXTLEN];
137 // set the default directory
138         sprintf(directory, "%shistogram.rc", BCASTDIR);
140 // load the defaults
141         defaults = new BC_Hash(directory);
142         defaults->load();
144         for(int j = 0; j < HISTOGRAM_MODES; j++)
145         {
146                 while(config.points[j].last) delete config.points[j].last;
148                 sprintf(string, "TOTAL_POINTS_%d", j);
149                 int total_points = defaults->get(string, 0);
151                 for(int i = 0; i < total_points; i++)
152                 {
153                         HistogramPoint *point = new HistogramPoint;
154                         sprintf(string, "INPUT_X_%d_%d", j, i);
155                         point->x = defaults->get(string, point->x);
156                         sprintf(string, "INPUT_Y_%d_%d", j, i);
157                         point->y = defaults->get(string, point->y);
158                         config.points[j].append(point);
159                 }
160         }
163         for(int i = 0; i < HISTOGRAM_MODES; i++)
164         {
165                 sprintf(string, "OUTPUT_MIN_%d", i);
166                 config.output_min[i] = defaults->get(string, config.output_min[i]);
167                 sprintf(string, "OUTPUT_MAX_%d", i);
168                 config.output_max[i] = defaults->get(string, config.output_max[i]);
169         }
171         config.automatic = defaults->get("AUTOMATIC", config.automatic);
172         mode = defaults->get("MODE", mode);
173         CLAMP(mode, 0, HISTOGRAM_MODES - 1);
174         config.threshold = defaults->get("THRESHOLD", config.threshold);
175         config.split = defaults->get("SPLIT", config.split);
176         config.boundaries();
177         return 0;
181 int HistogramMain::save_defaults()
183         char string[BCTEXTLEN];
187         for(int j = 0; j < HISTOGRAM_MODES; j++)
188         {
189                 int total_points = config.points[j].total();
190                 sprintf(string, "TOTAL_POINTS_%d", j);
191                 defaults->update(string, total_points);
192                 HistogramPoint *current = config.points[j].first;
193                 int number = 0;
194                 while(current)
195                 {
196                         sprintf(string, "INPUT_X_%d_%d", j, number);
197                         defaults->update(string, current->x);
198                         sprintf(string, "INPUT_Y_%d_%d", j, number);
199                         defaults->update(string, current->y);
200                         current = NEXT;
201                         number++;
202                 }
203         }
206         for(int i = 0; i < HISTOGRAM_MODES; i++)
207         {
208                 sprintf(string, "OUTPUT_MIN_%d", i);
209                 defaults->update(string, config.output_min[i]);
210                 sprintf(string, "OUTPUT_MAX_%d", i);
211                 defaults->update(string, config.output_max[i]);
212         }
214         defaults->update("AUTOMATIC", config.automatic);
215         defaults->update("MODE", mode);
216         defaults->update("THRESHOLD", config.threshold);
217         defaults->update("SPLIT", config.split);
218         defaults->save();
219         return 0;
224 void HistogramMain::save_data(KeyFrame *keyframe)
226         FileXML output;
228 // cause data to be stored directly in text
229         output.set_shared_string(keyframe->data, MESSAGESIZE);
230         output.tag.set_title("HISTOGRAM");
232         char string[BCTEXTLEN];
235         for(int i = 0; i < HISTOGRAM_MODES; i++)
236         {
237                 sprintf(string, "OUTPUT_MIN_%d", i);
238                 output.tag.set_property(string, config.output_min[i]);
239                 sprintf(string, "OUTPUT_MAX_%d", i);
240                 output.tag.set_property(string, config.output_max[i]);
241 //printf("HistogramMain::save_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
242         }
244         output.tag.set_property("AUTOMATIC", config.automatic);
245         output.tag.set_property("THRESHOLD", config.threshold);
246         output.tag.set_property("SPLIT", config.split);
247         output.append_tag();
248         output.append_newline();
254         for(int j = 0; j < HISTOGRAM_MODES; j++)
255         {
256                 output.tag.set_title("POINTS");
257                 output.append_tag();
258                 output.append_newline();
261                 HistogramPoint *current = config.points[j].first;
262                 while(current)
263                 {
264                         output.tag.set_title("POINT");
265                         output.tag.set_property("X", current->x);
266                         output.tag.set_property("Y", current->y);
267                         output.append_tag();
268                         output.append_newline();
269                         current = NEXT;
270                 }
273                 output.tag.set_title("/POINTS");
274                 output.append_tag();
275                 output.append_newline();
276         }
283         output.terminate_string();
286 void HistogramMain::read_data(KeyFrame *keyframe)
288         FileXML input;
290         input.set_shared_string(keyframe->data, strlen(keyframe->data));
292         int result = 0;
293         int current_input_mode = 0;
296         while(!result)
297         {
298                 result = input.read_tag();
300                 if(!result)
301                 {
302                         if(input.tag.title_is("HISTOGRAM"))
303                         {
304                                 char string[BCTEXTLEN];
305                                 for(int i = 0; i < HISTOGRAM_MODES; i++)
306                                 {
307                                         sprintf(string, "OUTPUT_MIN_%d", i);
308                                         config.output_min[i] = input.tag.get_property(string, config.output_min[i]);
309                                         sprintf(string, "OUTPUT_MAX_%d", i);
310                                         config.output_max[i] = input.tag.get_property(string, config.output_max[i]);
311 //printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
312                                 }
313                                 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
314                                 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
315                                 config.split = input.tag.get_property("SPLIT", config.split);
316                         }
317                         else
318                         if(input.tag.title_is("POINTS"))
319                         {
320                                 if(current_input_mode < HISTOGRAM_MODES)
321                                 {
322                                         HistogramPoints *points = &config.points[current_input_mode];
323                                         while(points->last) 
324                                                 delete points->last;
325                                         while(!result)
326                                         {
327                                                 result = input.read_tag();
328                                                 if(!result)
329                                                 {
330                                                         if(input.tag.title_is("/POINTS"))
331                                                         {
332                                                                 break;
333                                                         }
334                                                         else
335                                                         if(input.tag.title_is("POINT"))
336                                                         {
337                                                                 points->insert(
338                                                                         input.tag.get_property("X", 0.0),
339                                                                         input.tag.get_property("Y", 0.0));
340                                                         }
341                                                 }
342                                         }
344                                 }
345                                 current_input_mode++;
346                         }
347                 }
348         }
350         config.boundaries();
354 float HistogramMain::calculate_linear(float input, 
355         int subscript,
356         int use_value)
358         int done = 0;
359         float output;
361         if(input < 0)
362         {
363                 output = 0;
364                 done = 1;
365         }
367         if(input > 1)
368         {
369                 output = 1;
370                 done = 1;
371         }
373         if(!done)
374         {
376                 float x1 = 0;
377                 float y1 = 0;
378                 float x2 = 1;
379                 float y2 = 1;
383 // Get 2 points surrounding current position
384                 HistogramPoints *points = &config.points[subscript];
385                 HistogramPoint *current = points->first;
386                 int done = 0;
387                 while(current && !done)
388                 {
389                         if(current->x > input)
390                         {
391                                 x2 = current->x;
392                                 y2 = current->y;
393                                 done = 1;
394                         }
395                         else
396                                 current = NEXT;
397                 }
399                 current = points->last;
400                 done = 0;
401                 while(current && !done)
402                 {
403                         if(current->x <= input)
404                         {
405                                 x1 = current->x;
406                                 y1 = current->y;
407                                 done = 1;
408                         }
409                         else
410                                 current = PREVIOUS;
411                 }
416 // Linear
417                 if(!EQUIV(x2 - x1, 0))
418                         output = (input - x1) * (y2 - y1) / (x2 - x1) + y1;
419                 else
420                         output = input * y2;
426         }
428 // Apply value curve
429         if(use_value)
430         {
431                 output = calculate_linear(output, HISTOGRAM_VALUE, 0);
432         }
435         float output_min = config.output_min[subscript];
436         float output_max = config.output_max[subscript];
437         float output_left;
438         float output_right;
439         float output_linear;
441 // Compress output for value followed by channel
442         output = output_min + 
443                 output * 
444                 (output_max - output_min);
447         return output;
450 float HistogramMain::calculate_smooth(float input, int subscript)
452         float x_f = (input - MIN_INPUT) * HISTOGRAM_SLOTS / FLOAT_RANGE;
453         int x_i1 = (int)x_f;
454         int x_i2 = x_i1 + 1;
455         CLAMP(x_i1, 0, HISTOGRAM_SLOTS - 1);
456         CLAMP(x_i2, 0, HISTOGRAM_SLOTS - 1);
457         CLAMP(x_f, 0, HISTOGRAM_SLOTS - 1);
459         float smooth1 = smoothed[subscript][x_i1];
460         float smooth2 = smoothed[subscript][x_i2];
461         float result = smooth1 + (smooth2 - smooth1) * (x_f - x_i1);
462         CLAMP(result, 0, 1.0);
463         return result;
467 void HistogramMain::calculate_histogram(VFrame *data)
470         if(!engine) engine = new HistogramEngine(this,
471                 get_project_smp() + 1,
472                 get_project_smp() + 1);
474         if(!accum[0])
475         {
476                 for(int i = 0; i < HISTOGRAM_MODES; i++)
477                         accum[i] = new int[HISTOGRAM_SLOTS];
478         }
480         engine->process_packages(HistogramEngine::HISTOGRAM, data);
482         for(int i = 0; i < engine->get_total_clients(); i++)
483         {
484                 HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
486                 if(i == 0)
487                 {
488                         for(int j = 0; j < HISTOGRAM_MODES; j++)
489                         {
490                                 memcpy(accum[j], unit->accum[j], sizeof(int) * HISTOGRAM_SLOTS);
491                         }
492                 }
493                 else
494                 {
495                         for(int j = 0; j < HISTOGRAM_MODES; j++)
496                         {
497                                 int *out = accum[j];
498                                 int *in = unit->accum[j];
499                                 for(int k = 0; k < HISTOGRAM_SLOTS; k++)
500                                         out[k] += in[k];
501                         }
502                 }
503         }
505 // Remove top and bottom from calculations.  Doesn't work in high
506 // precision colormodels.
507         for(int i = 0; i < HISTOGRAM_MODES; i++)
508         {
509                 accum[i][0] = 0;
510                 accum[i][HISTOGRAM_SLOTS - 1] = 0;
511         }
515 void HistogramMain::calculate_automatic(VFrame *data)
517         calculate_histogram(data);
518         config.reset_points();
520 // Do each channel
521         for(int i = 0; i < 3; i++)
522         {
523                 int *accum = this->accum[i];
524                 int pixels = data->get_w() * data->get_h();
525                 float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
526                 int threshold = (int)(white_fraction * pixels);
527                 int total = 0;
528                 float max_level = 1.0;
529                 float min_level = 0.0;
531 // Get histogram slot above threshold of pixels
532                 for(int j = 0; j < HISTOGRAM_SLOTS; j++)
533                 {
534                         total += accum[j];
535                         if(total >= threshold)
536                         {
537                                 max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
538                                 break;
539                         }
540                 }
542 // Get slot below 99% of pixels
543                 total = 0;
544                 for(int j = HISTOGRAM_SLOTS - 1; j >= 0; j--)
545                 {
546                         total += accum[j];
547                         if(total >= threshold)
548                         {
549                                 min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
550                                 break;
551                         }
552                 }
555                 config.points[i].insert(max_level, 1.0);
556                 config.points[i].insert(min_level, 0.0);
557         }
565 int HistogramMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
567 SET_TRACE
568         int need_reconfigure = load_configuration();
571 SET_TRACE
573         if(!engine) engine = new HistogramEngine(this,
574                 get_project_smp() + 1,
575                 get_project_smp() + 1);
576         this->input = input_ptr;
577         this->output = output_ptr;
579         send_render_gui(input_ptr);
581         if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
582         {
583                 output_ptr->copy_from(input_ptr);
584         }
586 SET_TRACE
587 // Generate tables here.  The same table is used by many packages to render
588 // each horizontal stripe.  Need to cover the entire output range in  each
589 // table to avoid green borders
590         if(need_reconfigure || 
591                 !lookup[0] || 
592                 !smoothed[0] || 
593                 !linear[0] || 
594                 config.automatic)
595         {
596 SET_TRACE
597 // Calculate new curves
598                 if(config.automatic)
599                 {
600                         calculate_automatic(input);
601                 }
602 SET_TRACE
604 // Generate transfer tables for integer colormodels.
605                 for(int i = 0; i < 3; i++)
606                         tabulate_curve(i, 1);
607 SET_TRACE
608         }
612 // Apply histogram
613         engine->process_packages(HistogramEngine::APPLY, input);
615 SET_TRACE
617         return 0;
620 void HistogramMain::tabulate_curve(int subscript, int use_value)
622         int i;
623         if(!lookup[subscript])
624                 lookup[subscript] = new int[HISTOGRAM_SLOTS];
625         if(!smoothed[subscript])
626                 smoothed[subscript] = new float[HISTOGRAM_SLOTS];
627         if(!linear[subscript])
628                 linear[subscript] = new float[HISTOGRAM_SLOTS];
630         float *current_smooth = smoothed[subscript];
631         float *current_linear = linear[subscript];
633 // Make linear curve
634         for(i = 0; i < HISTOGRAM_SLOTS; i++)
635         {
636                 float input = (float)i / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
637                 current_linear[i] = calculate_linear(input, subscript, use_value);
638         }
645 // Make smooth curve (currently a copy of the linear curve)
646         float prev = 0.0;
647         for(i = 0; i < HISTOGRAM_SLOTS; i++)
648         {
649 //              current_smooth[i] = current_linear[i] * 0.001 +
650 //                      prev * 0.999;
651                 current_smooth[i] = current_linear[i];
652                 prev = current_smooth[i];
653         }
655 // Generate lookup tables for integer colormodels
656         if(input)
657         {
658                 switch(input->get_color_model())
659                 {
660                         case BC_RGB888:
661                         case BC_RGBA8888:
662                                 for(i = 0; i < 0x100; i++)
663                                         lookup[subscript][i] = 
664                                                 (int)(calculate_smooth((float)i / 0xff, subscript) * 0xff);
665                                 break;
666 // All other integer colormodels are converted to 16 bit RGB
667                         default:
668                                 for(i = 0; i < 0x10000; i++)
669                                         lookup[subscript][i] = 
670                                                 (int)(calculate_smooth((float)i / 0xffff, subscript) * 0xffff);
671                                 break;
672                 }
673         }
687 HistogramPackage::HistogramPackage()
688  : LoadPackage()
695 HistogramUnit::HistogramUnit(HistogramEngine *server, 
696         HistogramMain *plugin)
697  : LoadClient(server)
699         this->plugin = plugin;
700         this->server = server;
701         for(int i = 0; i < HISTOGRAM_MODES; i++)
702                 accum[i] = new int[HISTOGRAM_SLOTS];
705 HistogramUnit::~HistogramUnit()
707         for(int i = 0; i < HISTOGRAM_MODES; i++)
708                 delete [] accum[i];
711 void HistogramUnit::process_package(LoadPackage *package)
713         HistogramPackage *pkg = (HistogramPackage*)package;
715         if(server->operation == HistogramEngine::HISTOGRAM)
716         {
719 #define HISTOGRAM_HEAD(type) \
720 { \
721         for(int i = pkg->start; i < pkg->end; i++) \
722         { \
723                 type *row = (type*)data->get_rows()[i]; \
724                 for(int j = 0; j < w; j++) \
725                 {
727 #define HISTOGRAM_TAIL(components) \
728 /*                      v = (r * 76 + g * 150 + b * 29) >> 8; */ \
729                         v = MAX(r, g); \
730                         v = MAX(v, b); \
731                         r += -HISTOGRAM_MIN * 0xffff / 100; \
732                         g += -HISTOGRAM_MIN * 0xffff / 100; \
733                         b += -HISTOGRAM_MIN * 0xffff / 100; \
734                         v += -HISTOGRAM_MIN * 0xffff / 100; \
735                         CLAMP(r, 0, HISTOGRAM_SLOTS); \
736                         CLAMP(g, 0, HISTOGRAM_SLOTS); \
737                         CLAMP(b, 0, HISTOGRAM_SLOTS); \
738                         CLAMP(v, 0, HISTOGRAM_SLOTS); \
739                         accum_r[r]++; \
740                         accum_g[g]++; \
741                         accum_b[b]++; \
742                         accum_v[v]++; \
743                         row += components; \
744                 } \
745         } \
751                 VFrame *data = server->data;
752                 int w = data->get_w();
753                 int h = data->get_h();
754                 int *accum_r = accum[HISTOGRAM_RED];
755                 int *accum_g = accum[HISTOGRAM_GREEN];
756                 int *accum_b = accum[HISTOGRAM_BLUE];
757                 int *accum_v = accum[HISTOGRAM_VALUE];
758                 int r, g, b, a, y, u, v;
760                 switch(data->get_color_model())
761                 {
762                         case BC_RGB888:
763                                 HISTOGRAM_HEAD(unsigned char)
764                                 r = (row[0] << 8) | row[0];
765                                 g = (row[1] << 8) | row[1];
766                                 b = (row[2] << 8) | row[2];
767                                 HISTOGRAM_TAIL(3)
768                                 break;
769                         case BC_RGB_FLOAT:
770                                 HISTOGRAM_HEAD(float)
771                                 r = (int)(row[0] * 0xffff);
772                                 g = (int)(row[1] * 0xffff);
773                                 b = (int)(row[2] * 0xffff);
774                                 HISTOGRAM_TAIL(3)
775                                 break;
776                         case BC_YUV888:
777                                 HISTOGRAM_HEAD(unsigned char)
778                                 y = (row[0] << 8) | row[0];
779                                 u = (row[1] << 8) | row[1];
780                                 v = (row[2] << 8) | row[2];
781                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
782                                 HISTOGRAM_TAIL(3)
783                                 break;
784                         case BC_RGBA8888:
785                                 HISTOGRAM_HEAD(unsigned char)
786                                 r = (row[0] << 8) | row[0];
787                                 g = (row[1] << 8) | row[1];
788                                 b = (row[2] << 8) | row[2];
789                                 HISTOGRAM_TAIL(4)
790                                 break;
791                         case BC_RGBA_FLOAT:
792                                 HISTOGRAM_HEAD(float)
793                                 r = (int)(row[0] * 0xffff);
794                                 g = (int)(row[1] * 0xffff);
795                                 b = (int)(row[2] * 0xffff);
796                                 HISTOGRAM_TAIL(4)
797                                 break;
798                         case BC_YUVA8888:
799                                 HISTOGRAM_HEAD(unsigned char)
800                                 y = (row[0] << 8) | row[0];
801                                 u = (row[1] << 8) | row[1];
802                                 v = (row[2] << 8) | row[2];
803                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
804                                 HISTOGRAM_TAIL(4)
805                                 break;
806                         case BC_RGB161616:
807                                 HISTOGRAM_HEAD(uint16_t)
808                                 r = row[0];
809                                 g = row[1];
810                                 b = row[2];
811                                 HISTOGRAM_TAIL(3)
812                                 break;
813                         case BC_YUV161616:
814                                 HISTOGRAM_HEAD(uint16_t)
815                                 y = row[0];
816                                 u = row[1];
817                                 v = row[2];
818                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
819                                 HISTOGRAM_TAIL(3)
820                                 break;
821                         case BC_RGBA16161616:
822                                 HISTOGRAM_HEAD(uint16_t)
823                                 r = row[0];
824                                 g = row[1];
825                                 b = row[2];
826                                 HISTOGRAM_TAIL(3)
827                                 break;
828                         case BC_YUVA16161616:
829                                 HISTOGRAM_HEAD(uint16_t)
830                                 y = row[0];
831                                 u = row[1];
832                                 v = row[2];
833                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
834                                 HISTOGRAM_TAIL(4)
835                                 break;
836                 }
837         }
838         else
839         if(server->operation == HistogramEngine::APPLY)
840         {
844 #define PROCESS(type, components) \
845 { \
846         for(int i = pkg->start; i < pkg->end; i++) \
847         { \
848                 type *row = (type*)input->get_rows()[i]; \
849                 for(int j = 0; j < w; j++) \
850                 { \
851                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
852                         continue; \
853                         row[0] = lookup_r[row[0]]; \
854                         row[1] = lookup_g[row[1]]; \
855                         row[2] = lookup_b[row[2]]; \
856                         row += components; \
857                 } \
858         } \
861 #define PROCESS_YUV(type, components, max) \
862 { \
863         for(int i = pkg->start; i < pkg->end; i++) \
864         { \
865                 type *row = (type*)input->get_rows()[i]; \
866                 for(int j = 0; j < w; j++) \
867                 { \
868                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
869                         continue; \
870 /* Convert to 16 bit RGB */ \
871                         if(max == 0xff) \
872                         { \
873                                 y = (row[0] << 8) | row[0]; \
874                                 u = (row[1] << 8) | row[1]; \
875                                 v = (row[2] << 8) | row[2]; \
876                         } \
877                         else \
878                         { \
879                                 y = row[0]; \
880                                 u = row[1]; \
881                                 v = row[2]; \
882                         } \
884                         plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
886 /* Look up in RGB domain */ \
887                         r = lookup_r[r]; \
888                         g = lookup_g[g]; \
889                         b = lookup_b[b]; \
891 /* Convert to 16 bit YUV */ \
892                         plugin->yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
894                         if(max == 0xff) \
895                         { \
896                                 row[0] = y >> 8; \
897                                 row[1] = u >> 8; \
898                                 row[2] = v >> 8; \
899                         } \
900                         else \
901                         { \
902                                 row[0] = y; \
903                                 row[1] = u; \
904                                 row[2] = v; \
905                         } \
906                         row += components; \
907                 } \
908         } \
911 #define PROCESS_FLOAT(components) \
912 { \
913         for(int i = pkg->start; i < pkg->end; i++) \
914         { \
915                 float *row = (float*)input->get_rows()[i]; \
916                 for(int j = 0; j < w; j++) \
917                 { \
918                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
919                         continue; \
920                         float r = row[0]; \
921                         float g = row[1]; \
922                         float b = row[2]; \
924                         r = plugin->calculate_smooth(r, HISTOGRAM_RED); \
925                         g = plugin->calculate_smooth(g, HISTOGRAM_GREEN); \
926                         b = plugin->calculate_smooth(b, HISTOGRAM_BLUE); \
928                         row[0] = r; \
929                         row[1] = g; \
930                         row[2] = b; \
932                         row += components; \
933                 } \
934         } \
938                 VFrame *input = plugin->input;
939                 VFrame *output = plugin->output;
940                 int w = input->get_w();
941                 int h = input->get_h();
942                 int *lookup_r = plugin->lookup[0];
943                 int *lookup_g = plugin->lookup[1];
944                 int *lookup_b = plugin->lookup[2];
945                 int r, g, b, y, u, v, a;
946                 switch(input->get_color_model())
947                 {
948                         case BC_RGB888:
949                                 PROCESS(unsigned char, 3)
950                                 break;
951                         case BC_RGB_FLOAT:
952                                 PROCESS_FLOAT(3);
953                                 break;
954                         case BC_RGBA8888:
955                                 PROCESS(unsigned char, 4)
956                                 break;
957                         case BC_RGBA_FLOAT:
958                                 PROCESS_FLOAT(4);
959                                 break;
960                         case BC_RGB161616:
961                                 PROCESS(uint16_t, 3)
962                                 break;
963                         case BC_RGBA16161616:
964                                 PROCESS(uint16_t, 4)
965                                 break;
966                         case BC_YUV888:
967                                 PROCESS_YUV(unsigned char, 3, 0xff)
968                                 break;
969                         case BC_YUVA8888:
970                                 PROCESS_YUV(unsigned char, 4, 0xff)
971                                 break;
972                         case BC_YUV161616:
973                                 PROCESS_YUV(uint16_t, 3, 0xffff)
974                                 break;
975                         case BC_YUVA16161616:
976                                 PROCESS_YUV(uint16_t, 4, 0xffff)
977                                 break;
978                 }
979         }
987 HistogramEngine::HistogramEngine(HistogramMain *plugin, 
988         int total_clients, 
989         int total_packages)
990  : LoadServer(total_clients, total_packages)
992         this->plugin = plugin;
995 void HistogramEngine::init_packages()
997         switch(operation)
998         {
999                 case HISTOGRAM:
1000                         total_size = data->get_h();
1001                         break;
1002                 case APPLY:
1003                         total_size = data->get_h();
1004                         break;
1005         }
1008         int package_size = (int)((float)total_size / 
1009                         get_total_packages() + 1);
1010         int start = 0;
1012         for(int i = 0; i < get_total_packages(); i++)
1013         {
1014                 HistogramPackage *package = (HistogramPackage*)get_package(i);
1015                 package->start = total_size * i / get_total_packages();
1016                 package->end = total_size * (i + 1) / get_total_packages();
1017         }
1019 // Initialize clients here in case some don't get run.
1020         for(int i = 0; i < get_total_clients(); i++)
1021         {
1022                 HistogramUnit *unit = (HistogramUnit*)get_client(i);
1023                 for(int i = 0; i < HISTOGRAM_MODES; i++)
1024                         bzero(unit->accum[i], sizeof(int) * HISTOGRAM_SLOTS);
1025         }
1029 LoadClient* HistogramEngine::new_client()
1031         return new HistogramUnit(this, plugin);
1034 LoadPackage* HistogramEngine::new_package()
1036         return new HistogramPackage;
1039 void HistogramEngine::process_packages(int operation, VFrame *data)
1041         this->data = data;
1042         this->operation = operation;
1043         LoadServer::process_packages();