r864: Merge 2.1:
[cinelerra_cv/ct.git] / plugins / histogram / histogram.C
blobe4c65d579284b9faa137adc2627474135150e8e1
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                 preview_lookup[i] = 0;
55         }
56         current_point = -1;
57         mode = HISTOGRAM_VALUE;
58         dragging_point = 0;
59         input = 0;
60         output = 0;
63 HistogramMain::~HistogramMain()
65         PLUGIN_DESTRUCTOR_MACRO
66         for(int i = 0; i < HISTOGRAM_MODES;i++)
67         {
68                 delete [] lookup[i];
69                 delete [] smoothed[i];
70                 delete [] linear[i];
71                 delete [] accum[i];
72                 delete [] preview_lookup[i];
73         }
74         delete engine;
77 char* HistogramMain::plugin_title() { return N_("Histogram"); }
78 int HistogramMain::is_realtime() { return 1; }
81 #include "picon_png.h"
82 NEW_PICON_MACRO(HistogramMain)
84 SHOW_GUI_MACRO(HistogramMain, HistogramThread)
86 SET_STRING_MACRO(HistogramMain)
88 RAISE_WINDOW_MACRO(HistogramMain)
90 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
92 void HistogramMain::render_gui(void *data)
94         if(thread)
95         {
96 SET_TRACE
97 // Process just the RGB values to determine the automatic points or
98 // all the points if manual
99                 if(!config.automatic)
100                 {
101 // Generate curves for value histogram
102 // Lock out changes to curves
103                         thread->window->lock_window("HistogramMain::render_gui 1");
104                         tabulate_curve(HISTOGRAM_RED, 0);
105                         tabulate_curve(HISTOGRAM_GREEN, 0);
106                         tabulate_curve(HISTOGRAM_BLUE, 0);
107                         thread->window->unlock_window();
108                 }
110                 calculate_histogram((VFrame*)data, !config.automatic);
112 SET_TRACE
114                 if(config.automatic)
115                 {
116 SET_TRACE
117                         calculate_automatic((VFrame*)data);
119 SET_TRACE
120 // Generate curves for value histogram
121 // Lock out changes to curves
122                         thread->window->lock_window("HistogramMain::render_gui 1");
123                         tabulate_curve(HISTOGRAM_RED, 0);
124                         tabulate_curve(HISTOGRAM_GREEN, 0);
125                         tabulate_curve(HISTOGRAM_BLUE, 0);
126                         thread->window->unlock_window();
128 SET_TRACE
129 // Need a second pass to get the luminance values.
130                         calculate_histogram((VFrame*)data, 1);
131 SET_TRACE
132                 }
134 SET_TRACE
135                 thread->window->lock_window("HistogramMain::render_gui 2");
136                 thread->window->update_canvas();
137                 if(config.automatic)
138                 {
139                         thread->window->update_input();
140                 }
141                 thread->window->unlock_window();
142 SET_TRACE
143         }
146 void HistogramMain::update_gui()
148         if(thread)
149         {
150                 thread->window->lock_window("HistogramMain::update_gui");
151                 int reconfigure = load_configuration();
152                 if(reconfigure) 
153                 {
154                         thread->window->update(0);
155                         if(!config.automatic)
156                         {
157                                 thread->window->update_input();
158                         }
159                 }
160                 thread->window->unlock_window();
161         }
165 int HistogramMain::load_defaults()
167         char directory[BCTEXTLEN], string[BCTEXTLEN];
168 // set the default directory
169         sprintf(directory, "%shistogram.rc", BCASTDIR);
171 // load the defaults
172         defaults = new BC_Hash(directory);
173         defaults->load();
175         for(int j = 0; j < HISTOGRAM_MODES; j++)
176         {
177                 while(config.points[j].last) delete config.points[j].last;
179                 sprintf(string, "TOTAL_POINTS_%d", j);
180                 int total_points = defaults->get(string, 0);
182                 for(int i = 0; i < total_points; i++)
183                 {
184                         HistogramPoint *point = new HistogramPoint;
185                         sprintf(string, "INPUT_X_%d_%d", j, i);
186                         point->x = defaults->get(string, point->x);
187                         sprintf(string, "INPUT_Y_%d_%d", j, i);
188                         point->y = defaults->get(string, point->y);
189                         config.points[j].append(point);
190                 }
191         }
194         for(int i = 0; i < HISTOGRAM_MODES; i++)
195         {
196                 sprintf(string, "OUTPUT_MIN_%d", i);
197                 config.output_min[i] = defaults->get(string, config.output_min[i]);
198                 sprintf(string, "OUTPUT_MAX_%d", i);
199                 config.output_max[i] = defaults->get(string, config.output_max[i]);
200         }
202         config.automatic = defaults->get("AUTOMATIC", config.automatic);
203         mode = defaults->get("MODE", mode);
204         CLAMP(mode, 0, HISTOGRAM_MODES - 1);
205         config.threshold = defaults->get("THRESHOLD", config.threshold);
206         config.plot = defaults->get("PLOT", config.plot);
207         config.split = defaults->get("SPLIT", config.split);
208         config.boundaries();
209         return 0;
213 int HistogramMain::save_defaults()
215         char string[BCTEXTLEN];
219         for(int j = 0; j < HISTOGRAM_MODES; j++)
220         {
221                 int total_points = config.points[j].total();
222                 sprintf(string, "TOTAL_POINTS_%d", j);
223                 defaults->update(string, total_points);
224                 HistogramPoint *current = config.points[j].first;
225                 int number = 0;
226                 while(current)
227                 {
228                         sprintf(string, "INPUT_X_%d_%d", j, number);
229                         defaults->update(string, current->x);
230                         sprintf(string, "INPUT_Y_%d_%d", j, number);
231                         defaults->update(string, current->y);
232                         current = NEXT;
233                         number++;
234                 }
235         }
238         for(int i = 0; i < HISTOGRAM_MODES; i++)
239         {
240                 sprintf(string, "OUTPUT_MIN_%d", i);
241                 defaults->update(string, config.output_min[i]);
242                 sprintf(string, "OUTPUT_MAX_%d", i);
243                 defaults->update(string, config.output_max[i]);
244         }
246         defaults->update("AUTOMATIC", config.automatic);
247         defaults->update("MODE", mode);
248         defaults->update("THRESHOLD", config.threshold);
249         defaults->update("PLOT", config.plot);
250         defaults->update("SPLIT", config.split);
251         defaults->save();
252         return 0;
257 void HistogramMain::save_data(KeyFrame *keyframe)
259         FileXML output;
261 // cause data to be stored directly in text
262         output.set_shared_string(keyframe->data, MESSAGESIZE);
263         output.tag.set_title("HISTOGRAM");
265         char string[BCTEXTLEN];
268         for(int i = 0; i < HISTOGRAM_MODES; i++)
269         {
270                 sprintf(string, "OUTPUT_MIN_%d", i);
271                 output.tag.set_property(string, config.output_min[i]);
272                 sprintf(string, "OUTPUT_MAX_%d", i);
273                 output.tag.set_property(string, config.output_max[i]);
274 //printf("HistogramMain::save_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
275         }
277         output.tag.set_property("AUTOMATIC", config.automatic);
278         output.tag.set_property("THRESHOLD", config.threshold);
279         output.tag.set_property("PLOT", config.plot);
280         output.tag.set_property("SPLIT", config.split);
281         output.append_tag();
282         output.append_newline();
288         for(int j = 0; j < HISTOGRAM_MODES; j++)
289         {
290                 output.tag.set_title("POINTS");
291                 output.append_tag();
292                 output.append_newline();
295                 HistogramPoint *current = config.points[j].first;
296                 while(current)
297                 {
298                         output.tag.set_title("POINT");
299                         output.tag.set_property("X", current->x);
300                         output.tag.set_property("Y", current->y);
301                         output.append_tag();
302                         output.append_newline();
303                         current = NEXT;
304                 }
307                 output.tag.set_title("/POINTS");
308                 output.append_tag();
309                 output.append_newline();
310         }
317         output.terminate_string();
320 void HistogramMain::read_data(KeyFrame *keyframe)
322         FileXML input;
324         input.set_shared_string(keyframe->data, strlen(keyframe->data));
326         int result = 0;
327         int current_input_mode = 0;
330         while(!result)
331         {
332                 result = input.read_tag();
334                 if(!result)
335                 {
336                         if(input.tag.title_is("HISTOGRAM"))
337                         {
338                                 char string[BCTEXTLEN];
339                                 for(int i = 0; i < HISTOGRAM_MODES; i++)
340                                 {
341                                         sprintf(string, "OUTPUT_MIN_%d", i);
342                                         config.output_min[i] = input.tag.get_property(string, config.output_min[i]);
343                                         sprintf(string, "OUTPUT_MAX_%d", i);
344                                         config.output_max[i] = input.tag.get_property(string, config.output_max[i]);
345 //printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
346                                 }
347                                 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
348                                 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
349                                 config.plot = input.tag.get_property("PLOT", config.plot);
350                                 config.split = input.tag.get_property("SPLIT", config.split);
351                         }
352                         else
353                         if(input.tag.title_is("POINTS"))
354                         {
355                                 if(current_input_mode < HISTOGRAM_MODES)
356                                 {
357                                         HistogramPoints *points = &config.points[current_input_mode];
358                                         while(points->last) 
359                                                 delete points->last;
360                                         while(!result)
361                                         {
362                                                 result = input.read_tag();
363                                                 if(!result)
364                                                 {
365                                                         if(input.tag.title_is("/POINTS"))
366                                                         {
367                                                                 break;
368                                                         }
369                                                         else
370                                                         if(input.tag.title_is("POINT"))
371                                                         {
372                                                                 points->insert(
373                                                                         input.tag.get_property("X", 0.0),
374                                                                         input.tag.get_property("Y", 0.0));
375                                                         }
376                                                 }
377                                         }
379                                 }
380                                 current_input_mode++;
381                         }
382                 }
383         }
385         config.boundaries();
389 float HistogramMain::calculate_linear(float input, 
390         int subscript,
391         int use_value)
393         int done = 0;
394         float output;
396 //      if(input < 0)
397 //      {
398 //              output = 0;
399 //              done = 1;
400 //      }
401 // 
402 //      if(input > 1)
403 //      {
404 //              output = 1;
405 //              done = 1;
406 //      }
408         if(!done)
409         {
411                 float x1 = 0;
412                 float y1 = 0;
413                 float x2 = 1;
414                 float y2 = 1;
418 // Get 2 points surrounding current position
419                 HistogramPoints *points = &config.points[subscript];
420                 HistogramPoint *current = points->first;
421                 int done = 0;
422                 while(current && !done)
423                 {
424                         if(current->x > input)
425                         {
426                                 x2 = current->x;
427                                 y2 = current->y;
428                                 done = 1;
429                         }
430                         else
431                                 current = NEXT;
432                 }
434                 current = points->last;
435                 done = 0;
436                 while(current && !done)
437                 {
438                         if(current->x <= input)
439                         {
440                                 x1 = current->x;
441                                 y1 = current->y;
442                                 done = 1;
443                         }
444                         else
445                                 current = PREVIOUS;
446                 }
451 // Linear
452                 if(!EQUIV(x2 - x1, 0))
453                         output = (input - x1) * (y2 - y1) / (x2 - x1) + y1;
454                 else
455                         output = input * y2;
461         }
463 // Apply value curve
464         if(use_value)
465         {
466                 output = calculate_linear(output, HISTOGRAM_VALUE, 0);
467         }
470         float output_min = config.output_min[subscript];
471         float output_max = config.output_max[subscript];
472         float output_left;
473         float output_right;
474         float output_linear;
476 // Compress output for value followed by channel
477         output = output_min + 
478                 output * 
479                 (output_max - output_min);
482         return output;
485 float HistogramMain::calculate_smooth(float input, int subscript)
487         float x_f = (input - MIN_INPUT) * HISTOGRAM_SLOTS / FLOAT_RANGE;
488         int x_i1 = (int)x_f;
489         int x_i2 = x_i1 + 1;
490         CLAMP(x_i1, 0, HISTOGRAM_SLOTS - 1);
491         CLAMP(x_i2, 0, HISTOGRAM_SLOTS - 1);
492         CLAMP(x_f, 0, HISTOGRAM_SLOTS - 1);
494         float smooth1 = smoothed[subscript][x_i1];
495         float smooth2 = smoothed[subscript][x_i2];
496         float result = smooth1 + (smooth2 - smooth1) * (x_f - x_i1);
497         CLAMP(result, 0, 1.0);
498         return result;
502 void HistogramMain::calculate_histogram(VFrame *data, int do_value)
505         if(!engine) engine = new HistogramEngine(this,
506                 get_project_smp() + 1,
507                 get_project_smp() + 1);
509         if(!accum[0])
510         {
511                 for(int i = 0; i < HISTOGRAM_MODES; i++)
512                         accum[i] = new int[HISTOGRAM_SLOTS];
513         }
515         engine->process_packages(HistogramEngine::HISTOGRAM, data, do_value);
517         for(int i = 0; i < engine->get_total_clients(); i++)
518         {
519                 HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
521                 if(i == 0)
522                 {
523                         for(int j = 0; j < HISTOGRAM_MODES; j++)
524                         {
525                                 memcpy(accum[j], unit->accum[j], sizeof(int) * HISTOGRAM_SLOTS);
526                         }
527                 }
528                 else
529                 {
530                         for(int j = 0; j < HISTOGRAM_MODES; j++)
531                         {
532                                 int *out = accum[j];
533                                 int *in = unit->accum[j];
534                                 for(int k = 0; k < HISTOGRAM_SLOTS; k++)
535                                         out[k] += in[k];
536                         }
537                 }
538         }
540 // Remove top and bottom from calculations.  Doesn't work in high
541 // precision colormodels.
542         for(int i = 0; i < HISTOGRAM_MODES; i++)
543         {
544                 accum[i][0] = 0;
545                 accum[i][HISTOGRAM_SLOTS - 1] = 0;
546         }
550 void HistogramMain::calculate_automatic(VFrame *data)
552         calculate_histogram(data, 0);
553         config.reset_points(1);
555 // Do each channel
556         for(int i = 0; i < 3; i++)
557         {
558                 int *accum = this->accum[i];
559                 int pixels = data->get_w() * data->get_h();
560                 float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
561                 int threshold = (int)(white_fraction * pixels);
562                 int total = 0;
563                 float max_level = 1.0;
564                 float min_level = 0.0;
566 // Get histogram slot above threshold of pixels
567                 for(int j = 0; j < HISTOGRAM_SLOTS; j++)
568                 {
569                         total += accum[j];
570                         if(total >= threshold)
571                         {
572                                 max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
573                                 break;
574                         }
575                 }
577 // Get slot below 99% of pixels
578                 total = 0;
579                 for(int j = HISTOGRAM_SLOTS - 1; j >= 0; j--)
580                 {
581                         total += accum[j];
582                         if(total >= threshold)
583                         {
584                                 min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
585                                 break;
586                         }
587                 }
590                 config.points[i].insert(max_level, 1.0);
591                 config.points[i].insert(min_level, 0.0);
592         }
600 int HistogramMain::process_buffer(VFrame *frame,
601         int64_t start_position,
602         double frame_rate)
604 SET_TRACE
605         int need_reconfigure = load_configuration();
608 SET_TRACE
609         read_frame(frame, 
610                 0, 
611                 start_position, 
612                 frame_rate);
614         if(!engine) engine = new HistogramEngine(this,
615                 get_project_smp() + 1,
616                 get_project_smp() + 1);
617         this->input = frame;
618         this->output = frame;
620 // Always plot to set the curves if automatic
621         if(config.plot || config.automatic) send_render_gui(frame);
623 SET_TRACE
624 // Generate tables here.  The same table is used by many packages to render
625 // each horizontal stripe.  Need to cover the entire output range in  each
626 // table to avoid green borders
627         if(need_reconfigure || 
628                 !lookup[0] || 
629                 !smoothed[0] || 
630                 !linear[0] || 
631                 config.automatic)
632         {
633 SET_TRACE
634 // Calculate new curves
635                 if(config.automatic)
636                 {
637                         calculate_automatic(input);
638                 }
639 SET_TRACE
641 // Generate transfer tables with value function for integer colormodels.
642                 for(int i = 0; i < 3; i++)
643                         tabulate_curve(i, 1);
644 SET_TRACE
645         }
649 // Apply histogram
650         engine->process_packages(HistogramEngine::APPLY, input, 0);
652 SET_TRACE
654         return 0;
657 void HistogramMain::tabulate_curve(int subscript, int use_value)
659         int i;
660         if(!lookup[subscript])
661                 lookup[subscript] = new int[HISTOGRAM_SLOTS];
662         if(!smoothed[subscript])
663                 smoothed[subscript] = new float[HISTOGRAM_SLOTS];
664         if(!linear[subscript])
665                 linear[subscript] = new float[HISTOGRAM_SLOTS];
666         if(!preview_lookup[subscript])
667                 preview_lookup[subscript] = new int[HISTOGRAM_SLOTS];
670         float *current_smooth = smoothed[subscript];
671         float *current_linear = linear[subscript];
673 // Make linear curve
674         for(i = 0; i < HISTOGRAM_SLOTS; i++)
675         {
676                 float input = (float)i / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
677                 current_linear[i] = calculate_linear(input, subscript, use_value);
678         }
685 // Make smooth curve (currently a copy of the linear curve)
686         float prev = 0.0;
687         for(i = 0; i < HISTOGRAM_SLOTS; i++)
688         {
689 //              current_smooth[i] = current_linear[i] * 0.001 +
690 //                      prev * 0.999;
691 //              prev = current_smooth[i];
693                 current_smooth[i] = current_linear[i];
694         }
696 // Generate lookup tables for integer colormodels
697         if(input)
698         {
699                 switch(input->get_color_model())
700                 {
701                         case BC_RGB888:
702                         case BC_RGBA8888:
703                                 for(i = 0; i < 0x100; i++)
704                                         lookup[subscript][i] = 
705                                                 (int)(calculate_smooth((float)i / 0xff, subscript) * 0xff);
706                                 break;
707 // All other integer colormodels are converted to 16 bit RGB
708                         default:
709                                 for(i = 0; i < 0x10000; i++)
710                                         lookup[subscript][i] = 
711                                                 (int)(calculate_smooth((float)i / 0xffff, subscript) * 0xffff);
712                                 break;
713                 }
714         }
716 // Lookup table for preview only used for GUI
717         if(!use_value)
718         {
719                 for(i = 0; i < 0x10000; i++)
720                         preview_lookup[subscript][i] = 
721                                 (int)(calculate_smooth((float)i / 0xffff, subscript) * 0xffff);
722         }
735 HistogramPackage::HistogramPackage()
736  : LoadPackage()
743 HistogramUnit::HistogramUnit(HistogramEngine *server, 
744         HistogramMain *plugin)
745  : LoadClient(server)
747         this->plugin = plugin;
748         this->server = server;
749         for(int i = 0; i < HISTOGRAM_MODES; i++)
750                 accum[i] = new int[HISTOGRAM_SLOTS];
753 HistogramUnit::~HistogramUnit()
755         for(int i = 0; i < HISTOGRAM_MODES; i++)
756                 delete [] accum[i];
759 void HistogramUnit::process_package(LoadPackage *package)
761         HistogramPackage *pkg = (HistogramPackage*)package;
763         if(server->operation == HistogramEngine::HISTOGRAM)
764         {
765                 int do_value = server->do_value;
769 #define HISTOGRAM_HEAD(type) \
770 { \
771         for(int i = pkg->start; i < pkg->end; i++) \
772         { \
773                 type *row = (type*)data->get_rows()[i]; \
774                 for(int j = 0; j < w; j++) \
775                 {
777 #define HISTOGRAM_TAIL(components) \
778 /* Value takes the maximum of the output RGB values */ \
779                         if(do_value) \
780                         { \
781                                 CLAMP(r, 0, HISTOGRAM_SLOTS - 1); \
782                                 CLAMP(g, 0, HISTOGRAM_SLOTS - 1); \
783                                 CLAMP(b, 0, HISTOGRAM_SLOTS - 1); \
784                                 r_out = lookup_r[r]; \
785                                 g_out = lookup_g[g]; \
786                                 b_out = lookup_b[b]; \
787 /*                              v = (r * 76 + g * 150 + b * 29) >> 8; */ \
788                                 v = MAX(r_out, g_out); \
789                                 v = MAX(v, b_out); \
790                                 v += -HISTOGRAM_MIN * 0xffff / 100; \
791                                 CLAMP(v, 0, HISTOGRAM_SLOTS - 1); \
792                                 accum_v[v]++; \
793                         } \
795                         r += -HISTOGRAM_MIN * 0xffff / 100; \
796                         g += -HISTOGRAM_MIN * 0xffff / 100; \
797                         b += -HISTOGRAM_MIN * 0xffff / 100; \
798                         CLAMP(r, 0, HISTOGRAM_SLOTS - 1); \
799                         CLAMP(g, 0, HISTOGRAM_SLOTS - 1); \
800                         CLAMP(b, 0, HISTOGRAM_SLOTS - 1); \
801                         accum_r[r]++; \
802                         accum_g[g]++; \
803                         accum_b[b]++; \
804                         row += components; \
805                 } \
806         } \
812                 VFrame *data = server->data;
813                 int w = data->get_w();
814                 int h = data->get_h();
815                 int *accum_r = accum[HISTOGRAM_RED];
816                 int *accum_g = accum[HISTOGRAM_GREEN];
817                 int *accum_b = accum[HISTOGRAM_BLUE];
818                 int *accum_v = accum[HISTOGRAM_VALUE];
819                 int32_t r, g, b, a, y, u, v;
820                 int r_out, g_out, b_out;
821                 int *lookup_r = plugin->preview_lookup[HISTOGRAM_RED];
822                 int *lookup_g = plugin->preview_lookup[HISTOGRAM_GREEN];
823                 int *lookup_b = plugin->preview_lookup[HISTOGRAM_BLUE];
825                 switch(data->get_color_model())
826                 {
827                         case BC_RGB888:
828                                 HISTOGRAM_HEAD(unsigned char)
829                                 r = (row[0] << 8) | row[0];
830                                 g = (row[1] << 8) | row[1];
831                                 b = (row[2] << 8) | row[2];
832                                 HISTOGRAM_TAIL(3)
833                                 break;
834                         case BC_RGB_FLOAT:
835                                 HISTOGRAM_HEAD(float)
836                                 r = (int)(row[0] * 0xffff);
837                                 g = (int)(row[1] * 0xffff);
838                                 b = (int)(row[2] * 0xffff);
839                                 HISTOGRAM_TAIL(3)
840                                 break;
841                         case BC_YUV888:
842                                 HISTOGRAM_HEAD(unsigned char)
843                                 y = (row[0] << 8) | row[0];
844                                 u = (row[1] << 8) | row[1];
845                                 v = (row[2] << 8) | row[2];
846                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
847                                 HISTOGRAM_TAIL(3)
848                                 break;
849                         case BC_RGBA8888:
850                                 HISTOGRAM_HEAD(unsigned char)
851                                 r = (row[0] << 8) | row[0];
852                                 g = (row[1] << 8) | row[1];
853                                 b = (row[2] << 8) | row[2];
854                                 HISTOGRAM_TAIL(4)
855                                 break;
856                         case BC_RGBA_FLOAT:
857                                 HISTOGRAM_HEAD(float)
858                                 r = (int)(row[0] * 0xffff);
859                                 g = (int)(row[1] * 0xffff);
860                                 b = (int)(row[2] * 0xffff);
861                                 HISTOGRAM_TAIL(4)
862                                 break;
863                         case BC_YUVA8888:
864                                 HISTOGRAM_HEAD(unsigned char)
865                                 y = (row[0] << 8) | row[0];
866                                 u = (row[1] << 8) | row[1];
867                                 v = (row[2] << 8) | row[2];
868                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
869                                 HISTOGRAM_TAIL(4)
870                                 break;
871                         case BC_RGB161616:
872                                 HISTOGRAM_HEAD(uint16_t)
873                                 r = row[0];
874                                 g = row[1];
875                                 b = row[2];
876                                 HISTOGRAM_TAIL(3)
877                                 break;
878                         case BC_YUV161616:
879                                 HISTOGRAM_HEAD(uint16_t)
880                                 y = row[0];
881                                 u = row[1];
882                                 v = row[2];
883                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
884                                 HISTOGRAM_TAIL(3)
885                                 break;
886                         case BC_RGBA16161616:
887                                 HISTOGRAM_HEAD(uint16_t)
888                                 r = row[0];
889                                 g = row[1];
890                                 b = row[2];
891                                 HISTOGRAM_TAIL(3)
892                                 break;
893                         case BC_YUVA16161616:
894                                 HISTOGRAM_HEAD(uint16_t)
895                                 y = row[0];
896                                 u = row[1];
897                                 v = row[2];
898                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
899                                 HISTOGRAM_TAIL(4)
900                                 break;
901                 }
902         }
903         else
904         if(server->operation == HistogramEngine::APPLY)
905         {
909 #define PROCESS(type, components) \
910 { \
911         for(int i = pkg->start; i < pkg->end; i++) \
912         { \
913                 type *row = (type*)input->get_rows()[i]; \
914                 for(int j = 0; j < w; j++) \
915                 { \
916                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
917                         continue; \
918                         row[0] = lookup_r[row[0]]; \
919                         row[1] = lookup_g[row[1]]; \
920                         row[2] = lookup_b[row[2]]; \
921                         row += components; \
922                 } \
923         } \
926 #define PROCESS_YUV(type, components, max) \
927 { \
928         for(int i = pkg->start; i < pkg->end; i++) \
929         { \
930                 type *row = (type*)input->get_rows()[i]; \
931                 for(int j = 0; j < w; j++) \
932                 { \
933                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
934                         continue; \
935 /* Convert to 16 bit RGB */ \
936                         if(max == 0xff) \
937                         { \
938                                 y = (row[0] << 8) | row[0]; \
939                                 u = (row[1] << 8) | row[1]; \
940                                 v = (row[2] << 8) | row[2]; \
941                         } \
942                         else \
943                         { \
944                                 y = row[0]; \
945                                 u = row[1]; \
946                                 v = row[2]; \
947                         } \
949                         plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
951 /* Look up in RGB domain */ \
952                         r = lookup_r[r]; \
953                         g = lookup_g[g]; \
954                         b = lookup_b[b]; \
956 /* Convert to 16 bit YUV */ \
957                         plugin->yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
959                         if(max == 0xff) \
960                         { \
961                                 row[0] = y >> 8; \
962                                 row[1] = u >> 8; \
963                                 row[2] = v >> 8; \
964                         } \
965                         else \
966                         { \
967                                 row[0] = y; \
968                                 row[1] = u; \
969                                 row[2] = v; \
970                         } \
971                         row += components; \
972                 } \
973         } \
976 #define PROCESS_FLOAT(components) \
977 { \
978         for(int i = pkg->start; i < pkg->end; i++) \
979         { \
980                 float *row = (float*)input->get_rows()[i]; \
981                 for(int j = 0; j < w; j++) \
982                 { \
983                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
984                         continue; \
985                         float r = row[0]; \
986                         float g = row[1]; \
987                         float b = row[2]; \
989                         r = plugin->calculate_smooth(r, HISTOGRAM_RED); \
990                         g = plugin->calculate_smooth(g, HISTOGRAM_GREEN); \
991                         b = plugin->calculate_smooth(b, HISTOGRAM_BLUE); \
993                         row[0] = r; \
994                         row[1] = g; \
995                         row[2] = b; \
997                         row += components; \
998                 } \
999         } \
1003                 VFrame *input = plugin->input;
1004                 VFrame *output = plugin->output;
1005                 int w = input->get_w();
1006                 int h = input->get_h();
1007                 int *lookup_r = plugin->lookup[0];
1008                 int *lookup_g = plugin->lookup[1];
1009                 int *lookup_b = plugin->lookup[2];
1010                 int r, g, b, y, u, v, a;
1011                 switch(input->get_color_model())
1012                 {
1013                         case BC_RGB888:
1014                                 PROCESS(unsigned char, 3)
1015                                 break;
1016                         case BC_RGB_FLOAT:
1017                                 PROCESS_FLOAT(3);
1018                                 break;
1019                         case BC_RGBA8888:
1020                                 PROCESS(unsigned char, 4)
1021                                 break;
1022                         case BC_RGBA_FLOAT:
1023                                 PROCESS_FLOAT(4);
1024                                 break;
1025                         case BC_RGB161616:
1026                                 PROCESS(uint16_t, 3)
1027                                 break;
1028                         case BC_RGBA16161616:
1029                                 PROCESS(uint16_t, 4)
1030                                 break;
1031                         case BC_YUV888:
1032                                 PROCESS_YUV(unsigned char, 3, 0xff)
1033                                 break;
1034                         case BC_YUVA8888:
1035                                 PROCESS_YUV(unsigned char, 4, 0xff)
1036                                 break;
1037                         case BC_YUV161616:
1038                                 PROCESS_YUV(uint16_t, 3, 0xffff)
1039                                 break;
1040                         case BC_YUVA16161616:
1041                                 PROCESS_YUV(uint16_t, 4, 0xffff)
1042                                 break;
1043                 }
1044         }
1052 HistogramEngine::HistogramEngine(HistogramMain *plugin, 
1053         int total_clients, 
1054         int total_packages)
1055  : LoadServer(total_clients, total_packages)
1057         this->plugin = plugin;
1060 void HistogramEngine::init_packages()
1062         switch(operation)
1063         {
1064                 case HISTOGRAM:
1065                         total_size = data->get_h();
1066                         break;
1067                 case APPLY:
1068                         total_size = data->get_h();
1069                         break;
1070         }
1073         int package_size = (int)((float)total_size / 
1074                         get_total_packages() + 1);
1075         int start = 0;
1077         for(int i = 0; i < get_total_packages(); i++)
1078         {
1079                 HistogramPackage *package = (HistogramPackage*)get_package(i);
1080                 package->start = total_size * i / get_total_packages();
1081                 package->end = total_size * (i + 1) / get_total_packages();
1082         }
1084 // Initialize clients here in case some don't get run.
1085         for(int i = 0; i < get_total_clients(); i++)
1086         {
1087                 HistogramUnit *unit = (HistogramUnit*)get_client(i);
1088                 for(int i = 0; i < HISTOGRAM_MODES; i++)
1089                         bzero(unit->accum[i], sizeof(int) * HISTOGRAM_SLOTS);
1090         }
1094 LoadClient* HistogramEngine::new_client()
1096         return new HistogramUnit(this, plugin);
1099 LoadPackage* HistogramEngine::new_package()
1101         return new HistogramPackage;
1104 void HistogramEngine::process_packages(int operation, VFrame *data, int do_value)
1106         this->data = data;
1107         this->operation = operation;
1108         this->do_value = do_value;
1109         LoadServer::process_packages();