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