add histogram_bezier plugin
[goodguy/history.git] / cinelerra-5.0 / plugins / histogram_bezier / bistogram.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 "bistogram.h"
33 #include "bistogramconfig.h"
34 #include "bistogramwindow.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 REGISTER_PLUGIN(HistogramMain)
48
49 HistogramMain::HistogramMain(PluginServer *server)
50  : PluginVClient(server)
51 {
52         
53         engine = 0;
54         for(int i = 0; i < HISTOGRAM_MODES; i++)
55         {
56                 lookup[i] = 0;
57                 smoothed[i] = 0;
58                 linear[i] = 0;
59                 accum[i] = 0;
60         }
61         current_point = -1;
62         mode = HISTOGRAM_VALUE;
63         dragging_point = 0;
64         input = 0;
65         output = 0;
66 }
67
68 HistogramMain::~HistogramMain()
69 {
70         
71         for(int i = 0; i < HISTOGRAM_MODES;i++)
72         {
73                 delete [] lookup[i];
74                 delete [] smoothed[i];
75                 delete [] linear[i];
76                 delete [] accum[i];
77         }
78         delete engine;
79 }
80
81 const char* HistogramMain::plugin_title() { return _("Histogram Bezier"); }
82 int HistogramMain::is_realtime() { return 1; }
83
84
85 NEW_WINDOW_MACRO(HistogramMain, HistogramWindow)
86 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
87
88 void HistogramMain::render_gui(void *data)
89 {
90         if(thread)
91         {
92                 calculate_histogram((VFrame*)data);
93
94                 if(config.automatic)
95                 {
96                         calculate_automatic((VFrame*)data);
97                 }
98
99                 HistogramWindow *window = (HistogramWindow *)thread->window;
100                 window->lock_window("HistogramMain::render_gui");
101                 window->update_canvas();
102                 if(config.automatic)
103                 {
104                         window->update_input();
105                 }
106                 window->unlock_window();
107         }
108 }
109
110 void HistogramMain::update_gui()
111 {
112         if(thread)
113         {
114                 thread->window->lock_window("HistogramMain::update_gui");
115                 int reconfigure = load_configuration();
116                 if(reconfigure) 
117                 {
118                         HistogramWindow *window = (HistogramWindow *)thread->window;
119                         window->update(0);
120                         if(!config.automatic)
121                         {
122                                 window->update_input();
123                         }
124                 }
125                 thread->window->unlock_window();
126         }
127 }
128
129
130 void HistogramMain::save_data(KeyFrame *keyframe)
131 {
132         FileXML output;
133
134 // cause data to be stored directly in text
135         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
136         output.tag.set_title("HISTOGRAM");
137
138         char string[BCTEXTLEN];
139
140
141         for(int i = 0; i < HISTOGRAM_MODES; i++)
142         {
143                 sprintf(string, "OUTPUT_MIN_%d", i);
144                 output.tag.set_property(string, config.output_min[i]);
145                 sprintf(string, "OUTPUT_MAX_%d", i);
146                 output.tag.set_property(string, config.output_max[i]);
147 //printf("HistogramMain::save_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
148         }
149
150         output.tag.set_property("AUTOMATIC", config.automatic);
151         output.tag.set_property("THRESHOLD", config.threshold);
152         output.tag.set_property("SPLIT", config.split);
153         output.tag.set_property("INTERPOLATION", config.smoothMode);
154         output.append_tag();
155         output.tag.set_title("/HISTOGRAM");
156         output.append_tag();
157         output.append_newline();
158
159
160
161
162
163         for(int j = 0; j < HISTOGRAM_MODES; j++)
164         {
165                 output.tag.set_title("POINTS");
166                 output.append_tag();
167                 output.append_newline();
168
169
170                 HistogramPoint *current = config.points[j].first;
171                 while(current)
172                 {
173                         output.tag.set_title("POINT");
174                         output.tag.set_property("X", current->x);
175                         output.tag.set_property("Y", current->y);
176                         output.tag.set_property("GRADIENT", current->gradient);
177                         output.tag.set_property("XOFFSET_LEFT", current->xoffset_left);
178                         output.tag.set_property("XOFFSET_RIGHT", current->xoffset_right);
179                         output.append_tag();
180                         output.tag.set_title("/POINT");
181                         output.append_tag();
182                         output.append_newline();
183                         current = NEXT;
184                 }
185
186
187                 output.tag.set_title("/POINTS");
188                 output.append_tag();
189                 output.append_newline();
190         }
191
192
193
194
195
196
197         output.terminate_string();
198 }
199
200 void HistogramMain::read_data(KeyFrame *keyframe)
201 {
202         FileXML input;
203
204         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
205
206         int result = 0;
207         int current_input_mode = 0;
208
209
210         while(!result)
211         {
212                 result = input.read_tag();
213
214                 if(!result)
215                 {
216                         if(input.tag.title_is("HISTOGRAM"))
217                         {
218                                 char string[BCTEXTLEN];
219                                 for(int i = 0; i < HISTOGRAM_MODES; i++)
220                                 {
221                                         sprintf(string, "OUTPUT_MIN_%d", i);
222                                         config.output_min[i] = input.tag.get_property(string, config.output_min[i]);
223                                         sprintf(string, "OUTPUT_MAX_%d", i);
224                                         config.output_max[i] = input.tag.get_property(string, config.output_max[i]);
225 //printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
226                                 }
227                                 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
228                                 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
229                                 config.split = input.tag.get_property("SPLIT", config.split);
230                                 config.smoothMode = input.tag.get_property("INTERPOLATION", config.smoothMode);
231                         }
232                         else
233                         if(input.tag.title_is("POINTS"))
234                         {
235                                 if(current_input_mode < HISTOGRAM_MODES)
236                                 {
237                                         HistogramPoints *points = &config.points[current_input_mode];
238                                         while(points->last) 
239                                                 delete points->last;
240                                         while(!result)
241                                         {
242                                                 result = input.read_tag();
243                                                 if(!result)
244                                                 {
245                                                         if(input.tag.title_is("/POINTS"))
246                                                         {
247                                                                 break;
248                                                         }
249                                                         else
250                                                         if(input.tag.title_is("POINT"))
251                                                         {
252                                                                 points->insert(
253                                                                         input.tag.get_property("X", 0.0),
254                                                                         input.tag.get_property("Y", 0.0));
255                                                                 points->last->gradient = 
256                                                                         input.tag.get_property("GRADIENT", 1.0);
257                                                                 points->last->xoffset_left = 
258                                                                         input.tag.get_property("XOFFSET_LEFT", -0.02);
259                                                                 points->last->xoffset_right =
260                                                                         input.tag.get_property("XOFFSET_RIGHT", 0.02);
261                                                         }
262                                                 }
263                                         }
264
265                                 }
266                                 current_input_mode++;
267                         }
268                 }
269         }
270
271         config.boundaries();
272
273 }
274
275 float HistogramMain::calculate_linear(float input, 
276         int subscript,
277         int use_value)
278 {
279         int done = 0;
280         float output;
281
282         if(input < 0) {
283                 output = 0;
284                 done = 1;
285         }
286
287         if(input > 1) {
288                 output = 1;
289                 done = 1;
290         }
291
292         if(!done) {
293
294                 float x1 = 0, y1 = 0;
295                 float grad1 = 1.0;
296                 float x1right = 0;
297                 float x2 = 1, y2 = 1;
298                 float grad2 = 1.0;
299                 float x2left = 0;
300
301 // Get 2 points surrounding current position
302                 HistogramPoints *points = &config.points[subscript];
303                 HistogramPoint *current = points->first;
304                 int done = 0;
305                 while(current && !done) {
306                         if(current->x > input) {
307                                 x2 = current->x;
308                                 y2 = current->y;
309                                 grad2 = current->gradient;
310                                 x2left = current->xoffset_left;
311                                 done = 1;
312                         }
313                         else
314                                 current = NEXT;
315                 }
316
317                 current = points->last;
318                 done = 0;
319                 while(current && !done) {
320                         if(current->x <= input) {
321                                 x1 = current->x;
322                                 y1 = current->y;
323                                 grad1 = current->gradient;
324                                 done = 1;
325                                 x1right = current->xoffset_right;
326                         }
327                         else
328                                 current = PREVIOUS;
329                 }
330
331
332
333
334                 if(!EQUIV(x2 - x1, 0))
335                 {       
336                   if (config.smoothMode == HISTOGRAM_LINEAR)
337                         output = (input - x1) * (y2 - y1) / (x2 - x1) + y1;
338                   else if (config.smoothMode == HISTOGRAM_POLYNOMINAL)
339                   {
340                         /* Construct third grade polynom between every two points */
341                         float dx = x2 - x1;
342                         float dy = y2 - y1;
343                         float delx = input - x1;
344                         output = (grad2 * dx + grad1 * dx - 2*dy) / (dx * dx * dx) * delx * delx * delx +
345                          (dx * dx) * (3*dy - 2* grad1*dx - grad2*dx) / (dx * dx) * delx * delx + grad1*delx + y1;
346                   }
347                   else if (config.smoothMode == HISTOGRAM_BEZIER)
348                   {
349                         /* Using standart DeCasteljau algorithm */
350                         float y1right = y1 + grad1 * x1right;
351                         float y2left = y2 + grad2 * x2left;
352
353                         float t = (input - x1) / (x2 - x1);
354
355                         float pointAy = y1 + (y1right - y1) * t;
356                         float pointBy = y1right + (y2left - y1right) * t;
357                         float pointCy = y2left + (y2 - y2left) * t;
358                         float pointABy = pointAy + (pointBy - pointAy) * t;
359                         float pointBCy = pointBy + (pointCy - pointBy) * t;
360                         output = pointABy + (pointBCy - pointABy) * t;
361                   }
362                 }
363                 else
364 // Linear
365                         output = input * y2;
366         }
367
368 // Apply value curve
369         if(use_value) {
370                 output = calculate_linear(output, HISTOGRAM_VALUE, 0);
371         }
372
373
374         float output_min = config.output_min[subscript];
375         float output_max = config.output_max[subscript];
376
377 // Compress output for value followed by channel
378         output = output_min + output * (output_max - output_min);
379         return output;
380 }
381
382 float HistogramMain::calculate_smooth(float input, int subscript)
383 {
384         float x_f = (input - HIST_MIN_INPUT) * HISTOGRAM_SLOTS / FLOAT_RANGE;
385         int x_i1 = (int)x_f;
386         int x_i2 = x_i1 + 1;
387         CLAMP(x_i1, 0, HISTOGRAM_SLOTS-1);
388         CLAMP(x_i2, 0, HISTOGRAM_SLOTS-1);
389         CLAMP(x_f, 0, HISTOGRAM_SLOTS-1);
390
391         float smooth1 = smoothed[subscript][x_i1];
392         float smooth2 = smoothed[subscript][x_i2];
393         float result = smooth1 + (smooth2 - smooth1) * (x_f - x_i1);
394         CLAMP(result, 0, 1.0);
395         return result;
396 }
397
398
399 void HistogramMain::calculate_histogram(VFrame *data)
400 {
401
402         if(!engine) engine = new HistogramEngine(this,
403                 get_project_smp() + 1,
404                 get_project_smp() + 1);
405
406         if(!accum[0])
407         {
408                 for(int i = 0; i < HISTOGRAM_MODES; i++)
409                         accum[i] = new int[HISTOGRAM_SLOTS];
410         }
411         engine->process_packages(HistogramEngine::HISTOGRAM, data);
412
413         for(int i = 0; i < engine->get_total_clients(); i++) {
414                 HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
415                 if(i == 0) {
416                         for(int j = 0; j < HISTOGRAM_MODES; j++)
417                                 memcpy(accum[j], unit->accum[j], sizeof(int) * HISTOGRAM_SLOTS);
418                 }
419                 else {
420                         for(int j = 0; j < HISTOGRAM_MODES; j++) {
421                                 int *out = accum[j];
422                                 int *in = unit->accum[j];
423                                 for(int k = 0; k < HISTOGRAM_SLOTS; k++)
424                                         out[k] += in[k];
425                         }
426                 }
427         }
428
429 // Remove top and bottom from calculations.  Doesn't work in high
430 // precision colormodels.
431         for(int i = 0; i < HISTOGRAM_MODES; i++) {
432                 accum[i][0] = 0;
433                 accum[i][HISTOGRAM_SLOTS - 1] = 0;
434         }
435 }
436
437
438 void HistogramMain::calculate_automatic(VFrame *data)
439 {
440         calculate_histogram(data);
441         config.reset_points();
442
443 // Do each channel
444         for(int i = 0; i < 3; i++) {
445                 int *accum = this->accum[i];
446                 int pixels = data->get_w() * data->get_h();
447                 float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
448                 int threshold = (int)(white_fraction * pixels);
449                 int total = 0;
450                 float max_level = 1.0;
451                 float min_level = 0.0;
452
453 // Get histogram slot above threshold of pixels
454                 for(int j = 0; j < HISTOGRAM_SLOTS; j++) {
455                         total += accum[j];
456                         if(total >= threshold) {
457                                 max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
458                                 break;
459                         }
460                 }
461
462 // Get slot below 99% of pixels
463                 total = 0;
464                 for(int j = HISTOGRAM_SLOTS - 1; j >= 0; j--) {
465                         total += accum[j];
466                         if(total >= threshold) {
467                                 min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
468                                 break;
469                         }
470                 }
471                 config.points[i].insert(max_level, 1.0);
472                 config.points[i].insert(min_level, 0.0);
473         }
474 }
475
476 int HistogramMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
477 {
478 SET_TRACE
479         int need_reconfigure = load_configuration();
480 SET_TRACE
481
482         if(!engine) engine = new HistogramEngine(this,
483                 get_project_smp() + 1,
484                 get_project_smp() + 1);
485         this->input = input_ptr;
486         this->output = output_ptr;
487
488         send_render_gui(input_ptr);
489
490         if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
491         {
492                 output_ptr->copy_from(input_ptr);
493         }
494
495 SET_TRACE
496 // Generate tables here.  The same table is used by many packages to render
497 // each horizontal stripe.  Need to cover the entire output range in  each
498 // table to avoid green borders
499         if( !lookup[0] || !smoothed[0] || !linear[0] || config.automatic)
500                 need_reconfigure = 1;
501         if( need_reconfigure ) {
502 SET_TRACE
503 // Calculate new curves
504                 if(config.automatic) {
505                         calculate_automatic(input);
506                 }
507 SET_TRACE
508
509 // Generate transfer tables for integer colormodels.
510                 for(int i = 0; i < 3; i++)
511                         tabulate_curve(i, 1);
512 SET_TRACE
513         }
514
515 // Apply histogram
516         engine->process_packages(HistogramEngine::APPLY, input);
517
518 SET_TRACE
519         return 0;
520 }
521
522 void HistogramMain::tabulate_curve(int subscript, int use_value)
523 {
524         int i;
525         if(!lookup[subscript])
526                 lookup[subscript] = new int[HISTOGRAM_SLOTS];
527         if(!smoothed[subscript])
528                 smoothed[subscript] = new float[HISTOGRAM_SLOTS];
529         if(!linear[subscript])
530                 linear[subscript] = new float[HISTOGRAM_SLOTS];
531
532         float *current_smooth = smoothed[subscript];
533         float *current_linear = linear[subscript];
534
535 // Make linear curve
536         for(i = 0; i < HISTOGRAM_SLOTS; i++) {
537                 float input = (float)i / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
538                 current_linear[i] = calculate_linear(input, subscript, use_value);
539         }
540 // Make smooth curve
541         //float prev = 0.0;
542         for(i = 0; i < HISTOGRAM_SLOTS; i++)
543         {
544 //              current_smooth[i] = current_linear[i] * 0.001 +
545 //                      prev * 0.999;
546                 current_smooth[i] = current_linear[i];
547 //              prev = current_smooth[i];
548         }
549 // Generate lookup tables for integer colormodels
550         if(input)
551         {
552                 switch(input->get_color_model())
553                 {
554                         case BC_RGB888:
555                         case BC_RGBA8888:
556                                 for(i = 0; i < 0x100; i++)
557                                         lookup[subscript][i] = 
558                                                 (int)(calculate_smooth((float)i / 0xff, subscript) * 0xff);
559                                 break;
560 // All other integer colormodels are converted to 16 bit RGB
561                         default:
562                                 for(i = 0; i < 0x10000; i++)
563                                         lookup[subscript][i] = 
564                                                 (int)(calculate_smooth((float)i / 0xffff, subscript) * 0xffff);
565                                 break;
566                 }
567         }
568 }
569
570 HistogramPackage::HistogramPackage()
571  : LoadPackage()
572 {
573 }
574
575 HistogramUnit::HistogramUnit(HistogramEngine *server, 
576         HistogramMain *plugin)
577  : LoadClient(server)
578 {
579         this->plugin = plugin;
580         this->server = server;
581         for(int i = 0; i < HISTOGRAM_MODES; i++)
582                 accum[i] = new int[HISTOGRAM_SLOTS];
583 }
584
585 HistogramUnit::~HistogramUnit()
586 {
587         for(int i = 0; i < HISTOGRAM_MODES; i++)
588                 delete [] accum[i];
589 }
590
591 void HistogramUnit::process_package(LoadPackage *package)
592 {
593         HistogramPackage *pkg = (HistogramPackage*)package;
594
595         if(server->operation == HistogramEngine::HISTOGRAM)
596         {
597
598 #define HISTOGRAM_HEAD(type) \
599 { \
600         for(int i = pkg->start; i < pkg->end; i++) \
601         { \
602                 type *row = (type*)data->get_rows()[i]; \
603                 for(int j = 0; j < w; j++) \
604                 {
605
606 #define HISTOGRAM_TAIL(components) \
607 /*                      v = (r * 76 + g * 150 + b * 29) >> 8; */ \
608                         v = MAX(r, g); \
609                         v = MAX(v, b); \
610                         r += -HISTOGRAM_MIN * 0xffff / 100; \
611                         g += -HISTOGRAM_MIN * 0xffff / 100; \
612                         b += -HISTOGRAM_MIN * 0xffff / 100; \
613                         v += -HISTOGRAM_MIN * 0xffff / 100; \
614                         CLAMP(r, 0, HISTOGRAM_SLOTS-1); \
615                         CLAMP(g, 0, HISTOGRAM_SLOTS-1); \
616                         CLAMP(b, 0, HISTOGRAM_SLOTS-1); \
617                         CLAMP(v, 0, HISTOGRAM_SLOTS-1); \
618                         accum_r[r]++; \
619                         accum_g[g]++; \
620                         accum_b[b]++; \
621                         accum_v[v]++; \
622                         row += components; \
623                 } \
624         } \
625 }
626
627                 VFrame *data = server->data;
628                 int w = data->get_w();
629 //              int h = data->get_h();
630                 int *accum_r = accum[HISTOGRAM_RED];
631                 int *accum_g = accum[HISTOGRAM_GREEN];
632                 int *accum_b = accum[HISTOGRAM_BLUE];
633                 int *accum_v = accum[HISTOGRAM_VALUE];
634                 int r, g, b, y, u, v;
635
636                 switch(data->get_color_model())
637                 {
638                         case BC_RGB888:
639                                 HISTOGRAM_HEAD(unsigned char)
640                                 r = (row[0] << 8) | row[0];
641                                 g = (row[1] << 8) | row[1];
642                                 b = (row[2] << 8) | row[2];
643                                 HISTOGRAM_TAIL(3)
644                                 break;
645                         case BC_RGB_FLOAT:
646                                 HISTOGRAM_HEAD(float)
647                                 r = (int)(row[0] * 0xffff);
648                                 g = (int)(row[1] * 0xffff);
649                                 b = (int)(row[2] * 0xffff);
650                                 HISTOGRAM_TAIL(3)
651                                 break;
652                         case BC_YUV888:
653                                 HISTOGRAM_HEAD(unsigned char)
654                                 y = (row[0] << 8) | row[0];
655                                 u = (row[1] << 8) | row[1];
656                                 v = (row[2] << 8) | row[2];
657                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
658                                 HISTOGRAM_TAIL(3)
659                                 break;
660                         case BC_RGBA8888:
661                                 HISTOGRAM_HEAD(unsigned char)
662                                 r = (row[0] << 8) | row[0];
663                                 g = (row[1] << 8) | row[1];
664                                 b = (row[2] << 8) | row[2];
665                                 HISTOGRAM_TAIL(4)
666                                 break;
667                         case BC_RGBA_FLOAT:
668                                 HISTOGRAM_HEAD(float)
669                                 r = (int)(row[0] * 0xffff);
670                                 g = (int)(row[1] * 0xffff);
671                                 b = (int)(row[2] * 0xffff);
672                                 HISTOGRAM_TAIL(4)
673                                 break;
674                         case BC_YUVA8888:
675                                 HISTOGRAM_HEAD(unsigned char)
676                                 y = (row[0] << 8) | row[0];
677                                 u = (row[1] << 8) | row[1];
678                                 v = (row[2] << 8) | row[2];
679                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
680                                 HISTOGRAM_TAIL(4)
681                                 break;
682                         case BC_RGB161616:
683                                 HISTOGRAM_HEAD(uint16_t)
684                                 r = row[0];
685                                 g = row[1];
686                                 b = row[2];
687                                 HISTOGRAM_TAIL(3)
688                                 break;
689                         case BC_YUV161616:
690                                 HISTOGRAM_HEAD(uint16_t)
691                                 y = row[0];
692                                 u = row[1];
693                                 v = row[2];
694                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
695                                 HISTOGRAM_TAIL(3)
696                                 break;
697                         case BC_RGBA16161616:
698                                 HISTOGRAM_HEAD(uint16_t)
699                                 r = row[0];
700                                 g = row[1];
701                                 b = row[2];
702                                 HISTOGRAM_TAIL(3)
703                                 break;
704                         case BC_YUVA16161616:
705                                 HISTOGRAM_HEAD(uint16_t)
706                                 y = row[0];
707                                 u = row[1];
708                                 v = row[2];
709                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
710                                 HISTOGRAM_TAIL(4)
711                                 break;
712                 }
713         }
714         else
715         if(server->operation == HistogramEngine::APPLY)
716         {
717
718
719
720 #define PROCESS(type, components) \
721 { \
722         for(int i = pkg->start; i < pkg->end; i++) \
723         { \
724                 type *row = (type*)input->get_rows()[i]; \
725                 for(int j = 0; j < w; j++) \
726                 { \
727                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
728                         continue; \
729                         row[0] = lookup_r[row[0]]; \
730                         row[1] = lookup_g[row[1]]; \
731                         row[2] = lookup_b[row[2]]; \
732                         row += components; \
733                 } \
734         } \
735 }
736
737 #define PROCESS_YUV(type, components, max) \
738 { \
739         for(int i = pkg->start; i < pkg->end; i++) \
740         { \
741                 type *row = (type*)input->get_rows()[i]; \
742                 for(int j = 0; j < w; j++) \
743                 { \
744                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
745                         continue; \
746 /* Convert to 16 bit RGB */ \
747                         if(max == 0xff) \
748                         { \
749                                 y = (row[0] << 8) | row[0]; \
750                                 u = (row[1] << 8) | row[1]; \
751                                 v = (row[2] << 8) | row[2]; \
752                         } \
753                         else \
754                         { \
755                                 y = row[0]; \
756                                 u = row[1]; \
757                                 v = row[2]; \
758                         } \
759  \
760                         plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
761  \
762 /* Look up in RGB domain */ \
763                         r = lookup_r[r]; \
764                         g = lookup_g[g]; \
765                         b = lookup_b[b]; \
766  \
767 /* Convert to 16 bit YUV */ \
768                         plugin->yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
769  \
770                         if(max == 0xff) \
771                         { \
772                                 row[0] = y >> 8; \
773                                 row[1] = u >> 8; \
774                                 row[2] = v >> 8; \
775                         } \
776                         else \
777                         { \
778                                 row[0] = y; \
779                                 row[1] = u; \
780                                 row[2] = v; \
781                         } \
782                         row += components; \
783                 } \
784         } \
785 }
786
787 #define PROCESS_FLOAT(components) \
788 { \
789         for(int i = pkg->start; i < pkg->end; i++) \
790         { \
791                 float *row = (float*)input->get_rows()[i]; \
792                 for(int j = 0; j < w; j++) \
793                 { \
794                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
795                         continue; \
796                         float r = row[0]; \
797                         float g = row[1]; \
798                         float b = row[2]; \
799  \
800                         r = plugin->calculate_smooth(r, HISTOGRAM_RED); \
801                         g = plugin->calculate_smooth(g, HISTOGRAM_GREEN); \
802                         b = plugin->calculate_smooth(b, HISTOGRAM_BLUE); \
803  \
804                         row[0] = r; \
805                         row[1] = g; \
806                         row[2] = b; \
807  \
808                         row += components; \
809                 } \
810         } \
811 }
812
813
814                 VFrame *input = plugin->input;
815 //              VFrame *output = plugin->output;
816                 int w = input->get_w(), h = input->get_h();
817                 int *lookup_r = plugin->lookup[0];
818                 int *lookup_g = plugin->lookup[1];
819                 int *lookup_b = plugin->lookup[2];
820                 int r, g, b, y, u, v;
821                 switch(input->get_color_model())
822                 {
823                         case BC_RGB888:
824                                 PROCESS(unsigned char, 3)
825                                 break;
826                         case BC_RGB_FLOAT:
827                                 PROCESS_FLOAT(3);
828                                 break;
829                         case BC_RGBA8888:
830                                 PROCESS(unsigned char, 4)
831                                 break;
832                         case BC_RGBA_FLOAT:
833                                 PROCESS_FLOAT(4);
834                                 break;
835                         case BC_RGB161616:
836                                 PROCESS(uint16_t, 3)
837                                 break;
838                         case BC_RGBA16161616:
839                                 PROCESS(uint16_t, 4)
840                                 break;
841                         case BC_YUV888:
842                                 PROCESS_YUV(unsigned char, 3, 0xff)
843                                 break;
844                         case BC_YUVA8888:
845                                 PROCESS_YUV(unsigned char, 4, 0xff)
846                                 break;
847                         case BC_YUV161616:
848                                 PROCESS_YUV(uint16_t, 3, 0xffff)
849                                 break;
850                         case BC_YUVA16161616:
851                                 PROCESS_YUV(uint16_t, 4, 0xffff)
852                                 break;
853                 }
854         }
855 }
856
857
858
859
860
861
862 HistogramEngine::HistogramEngine(HistogramMain *plugin, 
863         int total_clients, 
864         int total_packages)
865  : LoadServer(total_clients, total_packages)
866 {
867         this->plugin = plugin;
868 }
869
870 void HistogramEngine::init_packages()
871 {
872         switch(operation) {
873                 case HISTOGRAM:
874                         total_size = data->get_h();
875                         break;
876                 case APPLY:
877                         total_size = data->get_h();
878                         break;
879         }
880
881         for(int i = 0; i < get_total_packages(); i++) {
882                 HistogramPackage *package = (HistogramPackage*)get_package(i);
883                 package->start = total_size * i / get_total_packages();
884                 package->end = total_size * (i + 1) / get_total_packages();
885         }
886
887 // Initialize clients here in case some don't get run.
888         for(int i = 0; i < get_total_clients(); i++) {
889                 HistogramUnit *unit = (HistogramUnit*)get_client(i);
890                 for(int i = 0; i < HISTOGRAM_MODES; i++)
891                         bzero(unit->accum[i], sizeof(int) * HISTOGRAM_SLOTS);
892         }
893
894 }
895
896 LoadClient* HistogramEngine::new_client()
897 {
898         return new HistogramUnit(this, plugin);
899 }
900
901 LoadPackage* HistogramEngine::new_package()
902 {
903         return new HistogramPackage;
904 }
905
906 void HistogramEngine::process_packages(int operation, VFrame *data)
907 {
908         this->data = data;
909         this->operation = operation;
910         LoadServer::process_packages();
911 }
912
913
914