initial commit
[goodguy/history.git] / cinelerra-5.0 / plugins / histogram_bezier / histogram.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  * 
20  */
21
22 #include <math.h>
23 #include <stdint.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "bcdisplayinfo.h"
28 #include "bcsignals.h"
29 #include "clip.h"
30 #include "bchash.h"
31 #include "filexml.h"
32 #include "histogram.h"
33 #include "histogramconfig.h"
34 #include "histogramwindow.h"
35 #include "keyframe.h"
36 #include "language.h"
37 #include "loadbalance.h"
38 #include "cicolors.h"
39 #include "vframe.h"
40
41
42
43 class HistogramMain;
44 class HistogramEngine;
45 class HistogramWindow;
46
47
48
49
50
51 REGISTER_PLUGIN(HistogramMain)
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 HistogramMain::HistogramMain(PluginServer *server)
68  : PluginVClient(server)
69 {
70         
71         engine = 0;
72         for(int i = 0; i < HISTOGRAM_MODES; i++)
73         {
74                 lookup[i] = 0;
75                 smoothed[i] = 0;
76                 linear[i] = 0;
77                 accum[i] = 0;
78         }
79         current_point = -1;
80         mode = HISTOGRAM_VALUE;
81         dragging_point = 0;
82         input = 0;
83         output = 0;
84 }
85
86 HistogramMain::~HistogramMain()
87 {
88         
89         for(int i = 0; i < HISTOGRAM_MODES;i++)
90         {
91                 delete [] lookup[i];
92                 delete [] smoothed[i];
93                 delete [] linear[i];
94                 delete [] accum[i];
95         }
96         delete engine;
97 }
98
99 char* HistogramMain::plugin_title() { return N_("Histogram"); }
100 int HistogramMain::is_realtime() { return 1; }
101
102
103
104 SHOW_GUI_MACRO(HistogramMain, HistogramThread)
105
106 SET_STRING_MACRO(HistogramMain)
107
108 RAISE_WINDOW_MACRO(HistogramMain)
109
110 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
111
112 void HistogramMain::render_gui(void *data)
113 {
114         if(thread)
115         {
116                 calculate_histogram((VFrame*)data);
117
118                 if(config.automatic)
119                 {
120                         calculate_automatic((VFrame*)data);
121                 }
122
123                 thread->window->lock_window("HistogramMain::render_gui");
124                 thread->window->update_canvas();
125                 if(config.automatic)
126                 {
127                         thread->window->update_input();
128                 }
129                 thread->window->unlock_window();
130         }
131 }
132
133 void HistogramMain::update_gui()
134 {
135         if(thread)
136         {
137                 thread->window->lock_window("HistogramMain::update_gui");
138                 int reconfigure = load_configuration();
139                 if(reconfigure) 
140                 {
141                         thread->window->update(0);
142                         if(!config.automatic)
143                         {
144                                 thread->window->update_input();
145                         }
146                 }
147                 thread->window->unlock_window();
148         }
149 }
150
151
152 int HistogramMain::load_defaults()
153 {
154         char directory[BCTEXTLEN], string[BCTEXTLEN];
155 // set the default directory
156         sprintf(directory, "%shistogram.rc", BCASTDIR);
157
158 // load the defaults
159         defaults = new BC_Hash(directory);
160         defaults->load();
161
162         for(int j = 0; j < HISTOGRAM_MODES; j++)
163         {
164                 while(config.points[j].last) delete config.points[j].last;
165
166                 sprintf(string, "TOTAL_POINTS_%d", j);
167                 int total_points = defaults->get(string, 0);
168
169                 for(int i = 0; i < total_points; i++)
170                 {
171                         HistogramPoint *point = new HistogramPoint;
172                         sprintf(string, "INPUT_X_%d_%d", j, i);
173                         point->x = defaults->get(string, point->x);
174                         sprintf(string, "INPUT_Y_%d_%d", j, i);
175                         point->y = defaults->get(string, point->y);
176                         sprintf(string, "GRADIENT_%d_%d", j, i);
177                         point->gradient = defaults->get(string, point->gradient);
178                         sprintf(string, "XOFFSET_LEFT_%d_%d", j, i);
179                         point->xoffset_left = defaults->get(string, point->xoffset_left);
180                         sprintf(string, "XOFFSET_RIGHT_%d_%d", j, i);
181                         point->xoffset_right = defaults->get(string, point->xoffset_right);
182                         config.points[j].append(point);
183                 }
184         }
185
186
187         for(int i = 0; i < HISTOGRAM_MODES; i++)
188         {
189                 sprintf(string, "OUTPUT_MIN_%d", i);
190                 config.output_min[i] = defaults->get(string, config.output_min[i]);
191                 sprintf(string, "OUTPUT_MAX_%d", i);
192                 config.output_max[i] = defaults->get(string, config.output_max[i]);
193         }
194
195         config.automatic = defaults->get("AUTOMATIC", config.automatic);
196         mode = defaults->get("MODE", mode);
197         CLAMP(mode, 0, HISTOGRAM_MODES - 1);
198         config.threshold = defaults->get("THRESHOLD", config.threshold);
199         config.split = defaults->get("SPLIT", config.split);
200         config.smoothMode = defaults->get("INTERPOLATION", config.smoothMode);
201         config.boundaries();
202         return 0;
203 }
204
205
206 int HistogramMain::save_defaults()
207 {
208         char string[BCTEXTLEN];
209
210
211
212         for(int j = 0; j < HISTOGRAM_MODES; j++)
213         {
214                 int total_points = config.points[j].total();
215                 sprintf(string, "TOTAL_POINTS_%d", j);
216                 defaults->update(string, total_points);
217                 HistogramPoint *current = config.points[j].first;
218                 int number = 0;
219                 while(current)
220                 {
221                         sprintf(string, "INPUT_X_%d_%d", j, number);
222                         defaults->update(string, current->x);
223                         sprintf(string, "INPUT_Y_%d_%d", j, number);
224                         defaults->update(string, current->y);
225                         sprintf(string, "GRADIENT_%d_%d", j, number);
226                         defaults->update(string, current->gradient);
227                         sprintf(string, "XOFFSET_LEFT_%d_%d", j, number);
228                         defaults->update(string, current->xoffset_left);
229                         sprintf(string, "XOFFSET_RIGHT_%d_%d", j, number);
230                         defaults->update(string, current->xoffset_right);                       
231                         current = NEXT;
232                         number++;
233                 }
234         }
235
236
237         for(int i = 0; i < HISTOGRAM_MODES; i++)
238         {
239                 sprintf(string, "OUTPUT_MIN_%d", i);
240                 defaults->update(string, config.output_min[i]);
241                 sprintf(string, "OUTPUT_MAX_%d", i);
242                 defaults->update(string, config.output_max[i]);
243         }
244
245         defaults->update("AUTOMATIC", config.automatic);
246         defaults->update("MODE", mode);
247         defaults->update("THRESHOLD", config.threshold);
248         defaults->update("SPLIT", config.split);
249         defaults->update("INTERPOLATION", config.smoothMode);
250         defaults->save();
251         return 0;
252 }
253
254
255
256 void HistogramMain::save_data(KeyFrame *keyframe)
257 {
258         FileXML output;
259
260 // cause data to be stored directly in text
261         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
262         output.tag.set_title("HISTOGRAM");
263
264         char string[BCTEXTLEN];
265
266
267         for(int i = 0; i < HISTOGRAM_MODES; i++)
268         {
269                 sprintf(string, "OUTPUT_MIN_%d", i);
270                 output.tag.set_property(string, config.output_min[i]);
271                 sprintf(string, "OUTPUT_MAX_%d", i);
272                 output.tag.set_property(string, config.output_max[i]);
273 //printf("HistogramMain::save_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
274         }
275
276         output.tag.set_property("AUTOMATIC", config.automatic);
277         output.tag.set_property("THRESHOLD", config.threshold);
278         output.tag.set_property("SPLIT", config.split);
279         output.tag.set_property("INTERPOLATION", config.smoothMode);
280         output.append_tag();
281         output.append_newline();
282
283
284
285
286
287         for(int j = 0; j < HISTOGRAM_MODES; j++)
288         {
289                 output.tag.set_title("POINTS");
290                 output.append_tag();
291                 output.append_newline();
292
293
294                 HistogramPoint *current = config.points[j].first;
295                 while(current)
296                 {
297                         output.tag.set_title("POINT");
298                         output.tag.set_property("X", current->x);
299                         output.tag.set_property("Y", current->y);
300                         output.tag.set_property("GRADIENT", current->gradient);
301                         output.tag.set_property("XOFFSET_LEFT", current->xoffset_left);
302                         output.tag.set_property("XOFFSET_RIGHT", current->xoffset_right);
303                         output.append_tag();
304                         output.append_newline();
305                         current = NEXT;
306                 }
307
308
309                 output.tag.set_title("/POINTS");
310                 output.append_tag();
311                 output.append_newline();
312         }
313
314
315
316
317
318
319         output.terminate_string();
320 }
321
322 void HistogramMain::read_data(KeyFrame *keyframe)
323 {
324         FileXML input;
325
326         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
327
328         int result = 0;
329         int current_input_mode = 0;
330
331
332         while(!result)
333         {
334                 result = input.read_tag();
335
336                 if(!result)
337                 {
338                         if(input.tag.title_is("HISTOGRAM"))
339                         {
340                                 char string[BCTEXTLEN];
341                                 for(int i = 0; i < HISTOGRAM_MODES; i++)
342                                 {
343                                         sprintf(string, "OUTPUT_MIN_%d", i);
344                                         config.output_min[i] = input.tag.get_property(string, config.output_min[i]);
345                                         sprintf(string, "OUTPUT_MAX_%d", i);
346                                         config.output_max[i] = input.tag.get_property(string, config.output_max[i]);
347 //printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
348                                 }
349                                 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
350                                 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
351                                 config.split = input.tag.get_property("SPLIT", config.split);
352                                 config.smoothMode = input.tag.get_property("INTERPOLATION", config.smoothMode);
353                         }
354                         else
355                         if(input.tag.title_is("POINTS"))
356                         {
357                                 if(current_input_mode < HISTOGRAM_MODES)
358                                 {
359                                         HistogramPoints *points = &config.points[current_input_mode];
360                                         while(points->last) 
361                                                 delete points->last;
362                                         while(!result)
363                                         {
364                                                 result = input.read_tag();
365                                                 if(!result)
366                                                 {
367                                                         if(input.tag.title_is("/POINTS"))
368                                                         {
369                                                                 break;
370                                                         }
371                                                         else
372                                                         if(input.tag.title_is("POINT"))
373                                                         {
374                                                                 points->insert(
375                                                                         input.tag.get_property("X", 0.0),
376                                                                         input.tag.get_property("Y", 0.0));
377                                                                 points->last->gradient = 
378                                                                         input.tag.get_property("GRADIENT", 1.0);
379                                                                 points->last->xoffset_left = 
380                                                                         input.tag.get_property("XOFFSET_LEFT", -0.02);
381                                                                 points->last->xoffset_right =
382                                                                         input.tag.get_property("XOFFSET_RIGHT", 0.02);
383                                                         }
384                                                 }
385                                         }
386
387                                 }
388                                 current_input_mode++;
389                         }
390                 }
391         }
392
393         config.boundaries();
394
395 }
396
397 float HistogramMain::calculate_linear(float input, 
398         int subscript,
399         int use_value)
400 {
401         int done = 0;
402         float output;
403
404         if(input < 0)
405         {
406                 output = 0;
407                 done = 1;
408         }
409
410         if(input > 1)
411         {
412                 output = 1;
413                 done = 1;
414         }
415
416         if(!done)
417         {
418
419                 float x1 = 0;
420                 float y1 = 0;
421                 float grad1 = 1.0;
422                 float x1right = 0;
423                 float x2 = 1;
424                 float y2 = 1;
425                 float grad2 = 1.0;
426                 float x2left = 0;
427
428
429
430 // Get 2 points surrounding current position
431                 HistogramPoints *points = &config.points[subscript];
432                 HistogramPoint *current = points->first;
433                 int done = 0;
434                 while(current && !done)
435                 {
436                         if(current->x > input)
437                         {
438                                 x2 = current->x;
439                                 y2 = current->y;
440                                 grad2 = current->gradient;
441                                 x2left = current->xoffset_left;
442                                 done = 1;
443                         }
444                         else
445                                 current = NEXT;
446                 }
447
448                 current = points->last;
449                 done = 0;
450                 while(current && !done)
451                 {
452                         if(current->x <= input)
453                         {
454                                 x1 = current->x;
455                                 y1 = current->y;
456                                 grad1 = current->gradient;
457                                 done = 1;
458                                 x1right = current->xoffset_right;
459                         }
460                         else
461                                 current = PREVIOUS;
462                 }
463
464
465
466
467                 if(!EQUIV(x2 - x1, 0))
468                 {       
469                   if (config.smoothMode == HISTOGRAM_LINEAR)
470                         output = (input - x1) * (y2 - y1) / (x2 - x1) + y1;
471                   else if (config.smoothMode == HISTOGRAM_POLYNOMINAL)
472                   {
473                         /* Construct third grade polynom between every two points */
474                         float dx = x2 - x1;
475                         float dy = y2 - y1;
476                         float delx = input - x1;
477                         output = 1 / (dx * dx * dx) * (grad2 * dx + grad1 * dx - 2*dy) * delx * delx * delx + 1 / (dx * dx) * (3*dy - 2* grad1*dx - grad2*dx) * delx * delx + grad1*delx + y1;
478                   }
479                   else if (config.smoothMode == HISTOGRAM_BEZIER)
480                   {
481                         /* Using standart DeCasteljau algorithm */
482                         float y1right = y1 + grad1 * x1right;
483                         float y2left = y2 + grad2 * x2left;
484
485                         float t = (input - x1) / (x2 - x1);
486
487                         float pointAy = y1 + (y1right - y1) * t;
488                         float pointBy = y1right + (y2left - y1right) * t;
489                         float pointCy = y2left + (y2 - y2left) * t;
490                         float pointABy = pointAy + (pointBy - pointAy) * t;
491                         float pointBCy = pointBy + (pointCy - pointBy) * t;
492                         output = pointABy + (pointBCy - pointABy) * t;
493                         
494                         }
495                 }
496                         
497                 else
498 // Linear
499                         output = input * y2;
500
501
502
503 // 
504
505
506         }
507
508 // Apply value curve
509         if(use_value)
510         {
511                 output = calculate_linear(output, HISTOGRAM_VALUE, 0);
512         }
513
514
515         float output_min = config.output_min[subscript];
516         float output_max = config.output_max[subscript];
517         float output_left;
518         float output_right;
519         float output_linear;
520
521 // Compress output for value followed by channel
522         output = output_min + 
523                 output * 
524                 (output_max - output_min);
525
526
527         return output;
528 }
529
530 float HistogramMain::calculate_smooth(float input, int subscript)
531 {
532         float x_f = (input - HIST_MIN_INPUT) * HISTOGRAM_SLOTS / FLOAT_RANGE;
533         int x_i1 = (int)x_f;
534         int x_i2 = x_i1 + 1;
535         CLAMP(x_i1, 0, HISTOGRAM_SLOTS - 1);
536         CLAMP(x_i2, 0, HISTOGRAM_SLOTS - 1);
537         CLAMP(x_f, 0, HISTOGRAM_SLOTS - 1);
538
539         float smooth1 = smoothed[subscript][x_i1];
540         float smooth2 = smoothed[subscript][x_i2];
541         float result = smooth1 + (smooth2 - smooth1) * (x_f - x_i1);
542         CLAMP(result, 0, 1.0);
543         return result;
544 }
545
546
547 void HistogramMain::calculate_histogram(VFrame *data)
548 {
549
550         if(!engine) engine = new HistogramEngine(this,
551                 get_project_smp() + 1,
552                 get_project_smp() + 1);
553
554         if(!accum[0])
555         {
556                 for(int i = 0; i < HISTOGRAM_MODES; i++)
557                         accum[i] = new int[HISTOGRAM_SLOTS];
558         }
559         engine->process_packages(HistogramEngine::HISTOGRAM, data);
560
561         for(int i = 0; i < engine->get_total_clients(); i++)
562         {
563                 HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
564                 if(i == 0)
565                 {
566                         for(int j = 0; j < HISTOGRAM_MODES; j++)
567                                 memcpy(accum[j], unit->accum[j], sizeof(int) * HISTOGRAM_SLOTS);
568                 }
569                 else
570                 {
571                         for(int j = 0; j < HISTOGRAM_MODES; j++)
572                         {
573                                 int *out = accum[j];
574                                 int *in = unit->accum[j];
575                                 for(int k = 0; k < HISTOGRAM_SLOTS; k++)
576                                         out[k] += in[k];
577                         }
578                 }
579         }
580
581 // Remove top and bottom from calculations.  Doesn't work in high
582 // precision colormodels.
583         for(int i = 0; i < HISTOGRAM_MODES; i++)
584         {
585                 accum[i][0] = 0;
586                 accum[i][HISTOGRAM_SLOTS - 1] = 0;
587         }
588 }
589
590
591 void HistogramMain::calculate_automatic(VFrame *data)
592 {
593         calculate_histogram(data);
594         config.reset_points();
595
596 // Do each channel
597         for(int i = 0; i < 3; i++)
598         {
599                 int *accum = this->accum[i];
600                 int pixels = data->get_w() * data->get_h();
601                 float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
602                 int threshold = (int)(white_fraction * pixels);
603                 int total = 0;
604                 float max_level = 1.0;
605                 float min_level = 0.0;
606
607 // Get histogram slot above threshold of pixels
608                 for(int j = 0; j < HISTOGRAM_SLOTS; j++)
609                 {
610                         total += accum[j];
611                         if(total >= threshold)
612                         {
613                                 max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
614                                 break;
615                         }
616                 }
617
618 // Get slot below 99% of pixels
619                 total = 0;
620                 for(int j = HISTOGRAM_SLOTS - 1; j >= 0; j--)
621                 {
622                         total += accum[j];
623                         if(total >= threshold)
624                         {
625                                 min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
626                                 break;
627                         }
628                 }
629
630
631                 config.points[i].insert(max_level, 1.0);
632                 config.points[i].insert(min_level, 0.0);
633
634         }
635 }
636
637
638
639
640
641
642 int HistogramMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
643 {
644 SET_TRACE
645         int need_reconfigure = load_configuration();
646
647 SET_TRACE
648
649         if(!engine) engine = new HistogramEngine(this,
650                 get_project_smp() + 1,
651                 get_project_smp() + 1);
652         this->input = input_ptr;
653         this->output = output_ptr;
654
655         send_render_gui(input_ptr);
656
657         if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
658         {
659                 output_ptr->copy_from(input_ptr);
660         }
661
662 SET_TRACE
663 // Generate tables here.  The same table is used by many packages to render
664 // each horizontal stripe.  Need to cover the entire output range in  each
665 // table to avoid green borders
666         if(need_reconfigure || 
667                 !lookup[0] || 
668                 !smoothed[0] || 
669                 !linear[0] || 
670                 config.automatic)
671         {
672 SET_TRACE
673 // Calculate new curves
674                 if(config.automatic)
675                 {
676                         calculate_automatic(input);
677                 }
678 SET_TRACE
679
680 // Generate transfer tables for integer colormodels.
681                 for(int i = 0; i < 3; i++)
682                         tabulate_curve(i, 1);
683 SET_TRACE
684         }
685
686
687
688
689 // Apply histogram
690         engine->process_packages(HistogramEngine::APPLY, input);
691
692 SET_TRACE
693
694         return 0;
695 }
696
697 void HistogramMain::tabulate_curve(int subscript, int use_value)
698 {
699         int i;
700         if(!lookup[subscript])
701                 lookup[subscript] = new int[HISTOGRAM_SLOTS];
702         if(!smoothed[subscript])
703                 smoothed[subscript] = new float[HISTOGRAM_SLOTS];
704         if(!linear[subscript])
705                 linear[subscript] = new float[HISTOGRAM_SLOTS];
706
707         float *current_smooth = smoothed[subscript];
708         float *current_linear = linear[subscript];
709
710 // Make linear curve
711         for(i = 0; i < HISTOGRAM_SLOTS; i++)
712         {
713                 float input = (float)i / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
714                 current_linear[i] = calculate_linear(input, subscript, use_value);
715         }
716
717
718
719
720
721
722 // Make smooth curve
723         float prev = 0.0;
724         for(i = 0; i < HISTOGRAM_SLOTS; i++)
725         {
726 //              current_smooth[i] = current_linear[i] * 0.001 +
727 //                      prev * 0.999;
728                 current_smooth[i] = current_linear[i];
729                 prev = current_smooth[i];
730         }
731
732
733 // Generate lookup tables for integer colormodels
734         if(input)
735         {
736                 switch(input->get_color_model())
737                 {
738                         case BC_RGB888:
739                         case BC_RGBA8888:
740                                 for(i = 0; i < 0x100; i++)
741                                         lookup[subscript][i] = 
742                                                 (int)(calculate_smooth((float)i / 0xff, subscript) * 0xff);
743                                 break;
744 // All other integer colormodels are converted to 16 bit RGB
745                         default:
746                                 for(i = 0; i < 0x10000; i++)
747                                         lookup[subscript][i] = 
748                                                 (int)(calculate_smooth((float)i / 0xffff, subscript) * 0xffff);
749                                 break;
750                 }
751         }
752 }
753
754
755
756
757
758
759
760
761
762
763
764
765 HistogramPackage::HistogramPackage()
766  : LoadPackage()
767 {
768 }
769
770
771
772
773 HistogramUnit::HistogramUnit(HistogramEngine *server, 
774         HistogramMain *plugin)
775  : LoadClient(server)
776 {
777         this->plugin = plugin;
778         this->server = server;
779         for(int i = 0; i < HISTOGRAM_MODES; i++)
780                 accum[i] = new int[HISTOGRAM_SLOTS];
781 }
782
783 HistogramUnit::~HistogramUnit()
784 {
785         for(int i = 0; i < HISTOGRAM_MODES; i++)
786                 delete [] accum[i];
787 }
788
789 void HistogramUnit::process_package(LoadPackage *package)
790 {
791         HistogramPackage *pkg = (HistogramPackage*)package;
792
793         if(server->operation == HistogramEngine::HISTOGRAM)
794         {
795
796 #define HISTOGRAM_HEAD(type) \
797 { \
798         for(int i = pkg->start; i < pkg->end; i++) \
799         { \
800                 type *row = (type*)data->get_rows()[i]; \
801                 for(int j = 0; j < w; j++) \
802                 {
803
804 #define HISTOGRAM_TAIL(components) \
805 /*                      v = (r * 76 + g * 150 + b * 29) >> 8; */ \
806                         v = MAX(r, g); \
807                         v = MAX(v, b); \
808                         r += -HISTOGRAM_MIN * 0xffff / 100; \
809                         g += -HISTOGRAM_MIN * 0xffff / 100; \
810                         b += -HISTOGRAM_MIN * 0xffff / 100; \
811                         v += -HISTOGRAM_MIN * 0xffff / 100; \
812                         CLAMP(r, 0, HISTOGRAM_SLOTS); \
813                         CLAMP(g, 0, HISTOGRAM_SLOTS); \
814                         CLAMP(b, 0, HISTOGRAM_SLOTS); \
815                         CLAMP(v, 0, HISTOGRAM_SLOTS); \
816                         accum_r[r]++; \
817                         accum_g[g]++; \
818                         accum_b[b]++; \
819                         accum_v[v]++; \
820                         row += components; \
821                 } \
822         } \
823 }
824
825
826
827
828                 VFrame *data = server->data;
829                 int w = data->get_w();
830                 int h = data->get_h();
831                 int *accum_r = accum[HISTOGRAM_RED];
832                 int *accum_g = accum[HISTOGRAM_GREEN];
833                 int *accum_b = accum[HISTOGRAM_BLUE];
834                 int *accum_v = accum[HISTOGRAM_VALUE];
835                 int r, g, b, a, y, u, v;
836
837                 switch(data->get_color_model())
838                 {
839                         case BC_RGB888:
840                                 HISTOGRAM_HEAD(unsigned char)
841                                 r = (row[0] << 8) | row[0];
842                                 g = (row[1] << 8) | row[1];
843                                 b = (row[2] << 8) | row[2];
844                                 HISTOGRAM_TAIL(3)
845                                 break;
846                         case BC_RGB_FLOAT:
847                                 HISTOGRAM_HEAD(float)
848                                 r = (int)(row[0] * 0xffff);
849                                 g = (int)(row[1] * 0xffff);
850                                 b = (int)(row[2] * 0xffff);
851                                 HISTOGRAM_TAIL(3)
852                                 break;
853                         case BC_YUV888:
854                                 HISTOGRAM_HEAD(unsigned char)
855                                 y = (row[0] << 8) | row[0];
856                                 u = (row[1] << 8) | row[1];
857                                 v = (row[2] << 8) | row[2];
858                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
859                                 HISTOGRAM_TAIL(3)
860                                 break;
861                         case BC_RGBA8888:
862                                 HISTOGRAM_HEAD(unsigned char)
863                                 r = (row[0] << 8) | row[0];
864                                 g = (row[1] << 8) | row[1];
865                                 b = (row[2] << 8) | row[2];
866                                 HISTOGRAM_TAIL(4)
867                                 break;
868                         case BC_RGBA_FLOAT:
869                                 HISTOGRAM_HEAD(float)
870                                 r = (int)(row[0] * 0xffff);
871                                 g = (int)(row[1] * 0xffff);
872                                 b = (int)(row[2] * 0xffff);
873                                 HISTOGRAM_TAIL(4)
874                                 break;
875                         case BC_YUVA8888:
876                                 HISTOGRAM_HEAD(unsigned char)
877                                 y = (row[0] << 8) | row[0];
878                                 u = (row[1] << 8) | row[1];
879                                 v = (row[2] << 8) | row[2];
880                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
881                                 HISTOGRAM_TAIL(4)
882                                 break;
883                         case BC_RGB161616:
884                                 HISTOGRAM_HEAD(uint16_t)
885                                 r = row[0];
886                                 g = row[1];
887                                 b = row[2];
888                                 HISTOGRAM_TAIL(3)
889                                 break;
890                         case BC_YUV161616:
891                                 HISTOGRAM_HEAD(uint16_t)
892                                 y = row[0];
893                                 u = row[1];
894                                 v = row[2];
895                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
896                                 HISTOGRAM_TAIL(3)
897                                 break;
898                         case BC_RGBA16161616:
899                                 HISTOGRAM_HEAD(uint16_t)
900                                 r = row[0];
901                                 g = row[1];
902                                 b = row[2];
903                                 HISTOGRAM_TAIL(3)
904                                 break;
905                         case BC_YUVA16161616:
906                                 HISTOGRAM_HEAD(uint16_t)
907                                 y = row[0];
908                                 u = row[1];
909                                 v = row[2];
910                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
911                                 HISTOGRAM_TAIL(4)
912                                 break;
913                 }
914         }
915         else
916         if(server->operation == HistogramEngine::APPLY)
917         {
918
919
920
921 #define PROCESS(type, components) \
922 { \
923         for(int i = pkg->start; i < pkg->end; i++) \
924         { \
925                 type *row = (type*)input->get_rows()[i]; \
926                 for(int j = 0; j < w; j++) \
927                 { \
928                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
929                         continue; \
930                         row[0] = lookup_r[row[0]]; \
931                         row[1] = lookup_g[row[1]]; \
932                         row[2] = lookup_b[row[2]]; \
933                         row += components; \
934                 } \
935         } \
936 }
937
938 #define PROCESS_YUV(type, components, max) \
939 { \
940         for(int i = pkg->start; i < pkg->end; i++) \
941         { \
942                 type *row = (type*)input->get_rows()[i]; \
943                 for(int j = 0; j < w; j++) \
944                 { \
945                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
946                         continue; \
947 /* Convert to 16 bit RGB */ \
948                         if(max == 0xff) \
949                         { \
950                                 y = (row[0] << 8) | row[0]; \
951                                 u = (row[1] << 8) | row[1]; \
952                                 v = (row[2] << 8) | row[2]; \
953                         } \
954                         else \
955                         { \
956                                 y = row[0]; \
957                                 u = row[1]; \
958                                 v = row[2]; \
959                         } \
960  \
961                         plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
962  \
963 /* Look up in RGB domain */ \
964                         r = lookup_r[r]; \
965                         g = lookup_g[g]; \
966                         b = lookup_b[b]; \
967  \
968 /* Convert to 16 bit YUV */ \
969                         plugin->yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
970  \
971                         if(max == 0xff) \
972                         { \
973                                 row[0] = y >> 8; \
974                                 row[1] = u >> 8; \
975                                 row[2] = v >> 8; \
976                         } \
977                         else \
978                         { \
979                                 row[0] = y; \
980                                 row[1] = u; \
981                                 row[2] = v; \
982                         } \
983                         row += components; \
984                 } \
985         } \
986 }
987
988 #define PROCESS_FLOAT(components) \
989 { \
990         for(int i = pkg->start; i < pkg->end; i++) \
991         { \
992                 float *row = (float*)input->get_rows()[i]; \
993                 for(int j = 0; j < w; j++) \
994                 { \
995                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
996                         continue; \
997                         float r = row[0]; \
998                         float g = row[1]; \
999                         float b = row[2]; \
1000  \
1001                         r = plugin->calculate_smooth(r, HISTOGRAM_RED); \
1002                         g = plugin->calculate_smooth(g, HISTOGRAM_GREEN); \
1003                         b = plugin->calculate_smooth(b, HISTOGRAM_BLUE); \
1004  \
1005                         row[0] = r; \
1006                         row[1] = g; \
1007                         row[2] = b; \
1008  \
1009                         row += components; \
1010                 } \
1011         } \
1012 }
1013
1014
1015                 VFrame *input = plugin->input;
1016                 VFrame *output = plugin->output;
1017                 int w = input->get_w();
1018                 int h = input->get_h();
1019                 int *lookup_r = plugin->lookup[0];
1020                 int *lookup_g = plugin->lookup[1];
1021                 int *lookup_b = plugin->lookup[2];
1022                 int r, g, b, y, u, v, a;
1023                 switch(input->get_color_model())
1024                 {
1025                         case BC_RGB888:
1026                                 PROCESS(unsigned char, 3)
1027                                 break;
1028                         case BC_RGB_FLOAT:
1029                                 PROCESS_FLOAT(3);
1030                                 break;
1031                         case BC_RGBA8888:
1032                                 PROCESS(unsigned char, 4)
1033                                 break;
1034                         case BC_RGBA_FLOAT:
1035                                 PROCESS_FLOAT(4);
1036                                 break;
1037                         case BC_RGB161616:
1038                                 PROCESS(uint16_t, 3)
1039                                 break;
1040                         case BC_RGBA16161616:
1041                                 PROCESS(uint16_t, 4)
1042                                 break;
1043                         case BC_YUV888:
1044                                 PROCESS_YUV(unsigned char, 3, 0xff)
1045                                 break;
1046                         case BC_YUVA8888:
1047                                 PROCESS_YUV(unsigned char, 4, 0xff)
1048                                 break;
1049                         case BC_YUV161616:
1050                                 PROCESS_YUV(uint16_t, 3, 0xffff)
1051                                 break;
1052                         case BC_YUVA16161616:
1053                                 PROCESS_YUV(uint16_t, 4, 0xffff)
1054                                 break;
1055                 }
1056         }
1057 }
1058
1059
1060
1061
1062
1063
1064 HistogramEngine::HistogramEngine(HistogramMain *plugin, 
1065         int total_clients, 
1066         int total_packages)
1067  : LoadServer(total_clients, total_packages)
1068 {
1069         this->plugin = plugin;
1070 }
1071
1072 void HistogramEngine::init_packages()
1073 {
1074         switch(operation)
1075         {
1076                 case HISTOGRAM:
1077                         total_size = data->get_h();
1078                         break;
1079                 case APPLY:
1080                         total_size = data->get_h();
1081                         break;
1082         }
1083
1084
1085         int package_size = (int)((float)total_size / 
1086                         get_total_packages() + 1);
1087         int start = 0;
1088
1089         for(int i = 0; i < get_total_packages(); i++)
1090         {
1091                 HistogramPackage *package = (HistogramPackage*)get_package(i);
1092                 package->start = total_size * i / get_total_packages();
1093                 package->end = total_size * (i + 1) / get_total_packages();
1094         }
1095
1096 // Initialize clients here in case some don't get run.
1097         for(int i = 0; i < get_total_clients(); i++)
1098         {
1099                 HistogramUnit *unit = (HistogramUnit*)get_client(i);
1100                 for(int i = 0; i < HISTOGRAM_MODES; i++)
1101                         bzero(unit->accum[i], sizeof(int) * HISTOGRAM_SLOTS);
1102         }
1103
1104 }
1105
1106 LoadClient* HistogramEngine::new_client()
1107 {
1108         return new HistogramUnit(this, plugin);
1109 }
1110
1111 LoadPackage* HistogramEngine::new_package()
1112 {
1113         return new HistogramPackage;
1114 }
1115
1116 void HistogramEngine::process_packages(int operation, VFrame *data)
1117 {
1118         this->data = data;
1119         this->operation = operation;
1120         LoadServer::process_packages();
1121 }
1122
1123
1124