yuv colorspace/range + prefs, ffmpeg colorrange probe, x11 direct force colormodel...
[goodguy/history.git] / cinelerra-5.1 / plugins / histogram / histogram.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008-2012 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 "playback3d.h"
39 #include "bccolors.h"
40 #include "vframe.h"
41 #include "workarounds.h"
42
43 #include "aggregated.h"
44 #include "../colorbalance/aggregated.h"
45 #include "../interpolate/aggregated.h"
46 #include "../gamma/aggregated.h"
47
48 class HistogramMain;
49 class HistogramEngine;
50 class HistogramWindow;
51
52
53
54
55
56 REGISTER_PLUGIN(HistogramMain)
57
58
59
60
61
62
63
64
65
66 HistogramMain::HistogramMain(PluginServer *server)
67  : PluginVClient(server)
68 {
69
70         engine = 0;
71         for(int i = 0; i < HISTOGRAM_MODES; i++)
72         {
73                 lookup[i] = 0;
74                 accum[i] = 0;
75                 preview_lookup[i] = 0;
76         }
77         current_point = -1;
78         mode = HISTOGRAM_VALUE;
79         dragging_point = 0;
80         input = 0;
81         output = 0;
82         w = 440;
83         h = 500;
84         parade = 0;
85 }
86
87 HistogramMain::~HistogramMain()
88 {
89
90         for(int i = 0; i < HISTOGRAM_MODES;i++)
91         {
92                 delete [] lookup[i];
93                 delete [] accum[i];
94                 delete [] preview_lookup[i];
95         }
96         delete engine;
97 }
98
99 const char* HistogramMain::plugin_title() { return _("Histogram"); }
100 int HistogramMain::is_realtime() { return 1; }
101
102
103
104 NEW_WINDOW_MACRO(HistogramMain, HistogramWindow)
105
106 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
107
108 void HistogramMain::render_gui(void *data)
109 {
110         if(thread)
111         {
112 // Process just the RGB values to determine the automatic points or
113 // all the points if manual
114                 if(!config.automatic)
115                 {
116 // Generate curves for value histogram
117 // Lock out changes to curves
118                         ((HistogramWindow*)thread->window)->lock_window("HistogramMain::render_gui 1");
119                         tabulate_curve(HISTOGRAM_RED, 0);
120                         tabulate_curve(HISTOGRAM_GREEN, 0);
121                         tabulate_curve(HISTOGRAM_BLUE, 0);
122                         ((HistogramWindow*)thread->window)->unlock_window();
123                 }
124
125                 calculate_histogram((VFrame*)data, !config.automatic);
126
127
128                 if(config.automatic)
129                 {
130                         calculate_automatic((VFrame*)data);
131
132 // Generate curves for value histogram
133 // Lock out changes to curves
134                         ((HistogramWindow*)thread->window)->lock_window("HistogramMain::render_gui 1");
135                         tabulate_curve(HISTOGRAM_RED, 0);
136                         tabulate_curve(HISTOGRAM_GREEN, 0);
137                         tabulate_curve(HISTOGRAM_BLUE, 0);
138                         ((HistogramWindow*)thread->window)->unlock_window();
139
140
141 // Need a second pass to get the luminance values.
142                         calculate_histogram((VFrame*)data, 1);
143                 }
144
145                 ((HistogramWindow*)thread->window)->lock_window("HistogramMain::render_gui 2");
146 // Always draw the histogram but don't update widgets if automatic
147                 ((HistogramWindow*)thread->window)->update(1,
148                         config.automatic && mode != HISTOGRAM_VALUE,
149                         config.automatic && mode != HISTOGRAM_VALUE,
150                         0);
151
152                 ((HistogramWindow*)thread->window)->unlock_window();
153         }
154 }
155
156 void HistogramMain::update_gui()
157 {
158         if(thread)
159         {
160                 ((HistogramWindow*)thread->window)->lock_window("HistogramMain::update_gui");
161                 int reconfigure = load_configuration();
162                 if(reconfigure)
163                 {
164                         ((HistogramWindow*)thread->window)->update(1,
165                                 1,
166                                 1,
167                                 1);
168                 }
169                 ((HistogramWindow*)thread->window)->unlock_window();
170         }
171 }
172
173
174
175
176 void HistogramMain::save_data(KeyFrame *keyframe)
177 {
178         FileXML output;
179
180 // cause data to be stored directly in text
181         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
182         output.tag.set_title("HISTOGRAM");
183
184         char string[BCTEXTLEN];
185
186         output.tag.set_property("AUTOMATIC", config.automatic);
187         output.tag.set_property("THRESHOLD", config.threshold);
188         output.tag.set_property("PLOT", config.plot);
189         output.tag.set_property("SPLIT", config.split);
190         output.tag.set_property("W", w);
191         output.tag.set_property("H", h);
192         output.tag.set_property("PARADE", parade);
193         output.tag.set_property("MODE", mode);
194
195         for(int i = 0; i < HISTOGRAM_MODES; i++)
196         {
197                 sprintf(string, "LOW_OUTPUT_%d", i);
198                 output.tag.set_property(string, config.low_output[i]);
199                 sprintf(string, "HIGH_OUTPUT_%d", i);
200                 output.tag.set_property(string, config.high_output[i]);
201                 sprintf(string, "LOW_INPUT_%d", i);
202                 output.tag.set_property(string, config.low_input[i]);
203                 sprintf(string, "HIGH_INPUT_%d", i);
204                 output.tag.set_property(string, config.high_input[i]);
205                 sprintf(string, "GAMMA_%d", i);
206                 output.tag.set_property(string, config.gamma[i]);
207 //printf("HistogramMain::save_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
208         }
209
210         output.append_tag();
211         output.tag.set_title("/HISTOGRAM");
212         output.append_tag();
213         output.append_newline();
214         output.terminate_string();
215 }
216
217 void HistogramMain::read_data(KeyFrame *keyframe)
218 {
219         FileXML input;
220
221         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
222
223         int result = 0;
224
225
226         while(!result)
227         {
228                 result = input.read_tag();
229
230                 if(!result)
231                 {
232                         if(input.tag.title_is("HISTOGRAM"))
233                         {
234                                 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
235                                 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
236                                 config.plot = input.tag.get_property("PLOT", config.plot);
237                                 config.split = input.tag.get_property("SPLIT", config.split);
238
239                                 if(is_defaults())
240                                 {
241                                         w = input.tag.get_property("W", w);
242                                         h = input.tag.get_property("H", h);
243                                         parade = input.tag.get_property("PARADE", parade);
244                                         mode = input.tag.get_property("MODE", mode);
245                                 }
246
247                                 char string[BCTEXTLEN];
248                                 for(int i = 0; i < HISTOGRAM_MODES; i++)
249                                 {
250                                         sprintf(string, "LOW_OUTPUT_%d", i);
251                                         config.low_output[i] = input.tag.get_property(string, config.low_output[i]);
252                                         sprintf(string, "HIGH_OUTPUT_%d", i);
253                                         config.high_output[i] = input.tag.get_property(string, config.high_output[i]);
254                                         sprintf(string, "GAMMA_%d", i);
255                                         config.gamma[i] = input.tag.get_property(string, config.gamma[i]);
256
257                                         if(i == HISTOGRAM_VALUE || !config.automatic)
258                                         {
259                                                 sprintf(string, "LOW_INPUT_%d", i);
260                                                 config.low_input[i] = input.tag.get_property(string, config.low_input[i]);
261                                                 sprintf(string, "HIGH_INPUT_%d", i);
262                                                 config.high_input[i] = input.tag.get_property(string, config.high_input[i]);
263                                         }
264 //printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
265                                 }
266                         }
267                 }
268         }
269
270         config.boundaries();
271
272 }
273
274 float HistogramMain::calculate_level(float input,
275         int mode,
276         int use_value)
277 {
278         float output = 0.0;
279
280 // Scale to input range
281         if(!EQUIV(config.high_input[mode], config.low_input[mode]))
282         {
283                 output = (input - config.low_input[mode]) /
284                         (config.high_input[mode] - config.low_input[mode]);
285         }
286         else
287         {
288                 output = input;
289         }
290
291
292
293         if(!EQUIV(config.gamma[mode], 0))
294         {
295                 output = pow(output, 1.0 / config.gamma[mode]);
296                 CLAMP(output, 0, 1.0);
297         }
298
299 // Apply value curve
300         if(use_value && mode != HISTOGRAM_VALUE)
301         {
302                 output = calculate_level(output, HISTOGRAM_VALUE, 0);
303         }
304
305
306
307
308 // scale to output range
309         if(!EQUIV(config.low_output[mode], config.high_output[mode]))
310         {
311                 output = output * (config.high_output[mode] - config.low_output[mode]) +
312                         config.low_output[mode];
313         }
314
315         CLAMP(output, 0, 1.0);
316
317         return output;
318 }
319
320
321
322 void HistogramMain::calculate_histogram(VFrame *data, int do_value)
323 {
324
325         if(!engine) engine = new HistogramEngine(this,
326                 get_project_smp() + 1,
327                 get_project_smp() + 1);
328
329         if(!accum[0])
330         {
331                 for(int i = 0; i < HISTOGRAM_MODES; i++)
332                         accum[i] = new int[HISTOGRAM_SLOTS];
333         }
334
335         engine->process_packages(HistogramEngine::HISTOGRAM, data, do_value);
336
337         for(int i = 0; i < engine->get_total_clients(); i++)
338         {
339                 HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
340
341                 if(i == 0)
342                 {
343                         for(int j = 0; j < HISTOGRAM_MODES; j++)
344                         {
345                                 memcpy(accum[j], unit->accum[j], sizeof(int) * HISTOGRAM_SLOTS);
346                         }
347                 }
348                 else
349                 {
350                         for(int j = 0; j < HISTOGRAM_MODES; j++)
351                         {
352                                 int *out = accum[j];
353                                 int *in = unit->accum[j];
354                                 for(int k = 0; k < HISTOGRAM_SLOTS; k++)
355                                         out[k] += in[k];
356                         }
357                 }
358         }
359
360 // Remove top and bottom from calculations.  Doesn't work in high
361 // precision colormodels.
362         for(int i = 0; i < HISTOGRAM_MODES; i++)
363         {
364                 accum[i][0] = 0;
365                 accum[i][HISTOGRAM_SLOTS - 1] = 0;
366         }
367 }
368
369
370 void HistogramMain::calculate_automatic(VFrame *data)
371 {
372         calculate_histogram(data, 0);
373         config.reset_points(1);
374
375 // Do each channel
376         for(int i = 0; i < 3; i++)
377         {
378                 int *accum = this->accum[i];
379                 int pixels = data->get_w() * data->get_h();
380                 float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
381                 int threshold = (int)(white_fraction * pixels);
382                 int total = 0;
383                 float max_level = 1.0;
384                 float min_level = 0.0;
385
386 // Get histogram slot above threshold of pixels
387                 for(int j = 0; j < HISTOGRAM_SLOTS; j++)
388                 {
389                         total += accum[j];
390                         if(total >= threshold)
391                         {
392                                 max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
393                                 break;
394                         }
395                 }
396
397 // Get slot below 99% of pixels
398                 total = 0;
399                 for(int j = HISTOGRAM_SLOTS - 1; j >= 0; j--)
400                 {
401                         total += accum[j];
402                         if(total >= threshold)
403                         {
404                                 min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
405                                 break;
406                         }
407                 }
408
409
410                 config.low_input[i] = min_level;
411                 config.high_input[i] = max_level;
412         }
413 }
414
415
416
417
418
419 int HistogramMain::calculate_use_opengl()
420 {
421 // glHistogram doesn't work.
422         int result = get_use_opengl() &&
423                 !config.automatic &&
424                 (!config.plot || !gui_open());
425         return result;
426 }
427
428
429 int HistogramMain::process_buffer(VFrame *frame,
430         int64_t start_position,
431         double frame_rate)
432 {
433         int need_reconfigure = load_configuration();
434
435
436
437         int use_opengl = calculate_use_opengl();
438
439 //printf("%d\n", use_opengl);
440         read_frame(frame,
441                 0,
442                 start_position,
443                 frame_rate,
444                 use_opengl);
445
446 // Apply histogram in hardware
447         if(use_opengl) return run_opengl();
448
449         if(!engine) engine = new HistogramEngine(this,
450                 get_project_smp() + 1,
451                 get_project_smp() + 1);
452         this->input = frame;
453         this->output = frame;
454 // Always plot to set the curves if automatic
455         if(config.plot || config.automatic) send_render_gui(frame);
456
457 // Generate tables here.  The same table is used by many packages to render
458 // each horizontal stripe.  Need to cover the entire output range in  each
459 // table to avoid green borders
460
461
462         if(need_reconfigure ||
463                 !lookup[0] ||
464                 config.automatic)
465         {
466 // Calculate new curves
467                 if(config.automatic)
468                 {
469                         calculate_automatic(input);
470                 }
471
472
473 // Generate transfer tables with value function for integer colormodels.
474                 for(int i = 0; i < 3; i++)
475                         tabulate_curve(i, 1);
476         }
477
478 // printf("HistogramMain::process_buffer %d %f %f %f  %f %f %f  %f %f %f\n",
479 // __LINE__,
480 // config.low_input[HISTOGRAM_RED],
481 // config.gamma[HISTOGRAM_RED],
482 // config.high_input[HISTOGRAM_RED],
483 // config.low_input[HISTOGRAM_GREEN],
484 // config.gamma[HISTOGRAM_GREEN],
485 // config.high_input[HISTOGRAM_GREEN],
486 // config.low_input[HISTOGRAM_BLUE],
487 // config.gamma[HISTOGRAM_BLUE],
488 // config.high_input[HISTOGRAM_BLUE]);
489
490
491
492 // Apply histogram
493         engine->process_packages(HistogramEngine::APPLY, input, 0);
494
495
496         return 0;
497 }
498
499 void HistogramMain::tabulate_curve(int subscript, int use_value)
500 {
501         int i;
502         if(!lookup[subscript])
503                 lookup[subscript] = new int[HISTOGRAM_SLOTS];
504         if(!preview_lookup[subscript])
505                 preview_lookup[subscript] = new int[HISTOGRAM_SLOTS];
506
507 //printf("HistogramMain::tabulate_curve %d input=%p\n", __LINE__, input);
508
509
510 // Generate lookup tables for integer colormodels
511         if(input)
512         {
513                 switch(input->get_color_model())
514                 {
515                         case BC_RGB888:
516                         case BC_RGBA8888:
517                                 for(i = 0; i < 0x100; i++)
518                                 {
519                                         lookup[subscript][i] =
520                                                 (int)(calculate_level((float)i / 0xff, subscript, use_value) *
521                                                 0xff);
522                                         CLAMP(lookup[subscript][i], 0, 0xff);
523                                 }
524                                 break;
525 // All other integer colormodels are converted to 16 bit RGB
526                         default:
527                                 for(i = 0; i < 0x10000; i++)
528                                 {
529                                         lookup[subscript][i] =
530                                                 (int)(calculate_level((float)i / 0xffff, subscript, use_value) *
531                                                 0xffff);
532                                         CLAMP(lookup[subscript][i], 0, 0xffff);
533                                 }
534 // for(i = 0; i < 0x100; i++)
535 // {
536 // if(subscript == HISTOGRAM_BLUE) printf("%d ", lookup[subscript][i * 0x100]);
537 // }
538 // if(subscript == HISTOGRAM_BLUE) printf("\n");
539
540                                 break;
541                 }
542         }
543
544 // Lookup table for preview only used for GUI
545         if(!use_value)
546         {
547                 for(i = 0; i < 0x10000; i++)
548                 {
549                         preview_lookup[subscript][i] =
550                                 (int)(calculate_level((float)i / 0xffff, subscript, use_value) *
551                                 0xffff);
552                         CLAMP(preview_lookup[subscript][i], 0, 0xffff);
553                 }
554         }
555 }
556
557 int HistogramMain::handle_opengl()
558 {
559 #ifdef HAVE_GL
560 // Functions to get pixel from either previous effect or texture
561         static const char *histogram_get_pixel1 =
562                 "vec4 histogram_get_pixel()\n"
563                 "{\n"
564                 "       return gl_FragColor;\n"
565                 "}\n";
566
567         static const char *histogram_get_pixel2 =
568                 "uniform sampler2D tex;\n"
569                 "vec4 histogram_get_pixel()\n"
570                 "{\n"
571                 "       return texture2D(tex, gl_TexCoord[0].st);\n"
572                 "}\n";
573
574         static const char *head_frag =
575                 "uniform vec4 low_input;\n"
576                 "uniform vec4 high_input;\n"
577                 "uniform vec4 gamma;\n"
578                 "uniform vec4 low_output;\n"
579                 "uniform vec4 output_scale;\n"
580                 "void main()\n"
581                 "{\n"
582                 "       float temp = 0.0;\n";
583
584         static const char *get_rgb_frag =
585                 "       vec4 pixel = histogram_get_pixel();\n";
586
587         static const char *get_yuv_frag =
588                 "       vec4 pixel = histogram_get_pixel();\n"
589                         YUV_TO_RGB_FRAG("pixel");
590
591 #define APPLY_INPUT_CURVE(PIXEL, LOW_INPUT, HIGH_INPUT, GAMMA) \
592                 "// apply input curve\n" \
593                 "       temp = (" PIXEL " - " LOW_INPUT ") / \n" \
594                 "               (" HIGH_INPUT " - " LOW_INPUT ");\n" \
595                 "       temp = max(temp, 0.0);\n" \
596                 "       " PIXEL " = pow(temp, 1.0 / " GAMMA ");\n"
597
598
599
600         static const char *apply_histogram_frag =
601                 APPLY_INPUT_CURVE("pixel.r", "low_input.r", "high_input.r", "gamma.r")
602                 APPLY_INPUT_CURVE("pixel.g", "low_input.g", "high_input.g", "gamma.g")
603                 APPLY_INPUT_CURVE("pixel.b", "low_input.b", "high_input.b", "gamma.b")
604                 "// apply output curve\n"
605                 "       pixel.rgb *= output_scale.rgb;\n"
606                 "       pixel.rgb += low_output.rgb;\n"
607                 APPLY_INPUT_CURVE("pixel.r", "low_input.a", "high_input.a", "gamma.a")
608                 APPLY_INPUT_CURVE("pixel.g", "low_input.a", "high_input.a", "gamma.a")
609                 APPLY_INPUT_CURVE("pixel.b", "low_input.a", "high_input.a", "gamma.a")
610                 "// apply output curve\n"
611                 "       pixel.rgb *= vec3(output_scale.a, output_scale.a, output_scale.a);\n"
612                 "       pixel.rgb += vec3(low_output.a, low_output.a, low_output.a);\n";
613
614         static const char *put_rgb_frag =
615                 "       gl_FragColor = pixel;\n"
616                 "}\n";
617
618         static const char *put_yuv_frag =
619                         RGB_TO_YUV_FRAG("pixel")
620                 "       gl_FragColor = pixel;\n"
621                 "}\n";
622
623
624
625         get_output()->to_texture();
626         get_output()->enable_opengl();
627
628         const char *shader_stack[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
629         int current_shader = 0;
630         int aggregate_interpolation = 0;
631         int aggregate_gamma = 0;
632         int aggregate_colorbalance = 0;
633 // All aggregation possibilities must be accounted for because unsupported
634 // effects can get in between the aggregation members.
635         if(!strcmp(get_output()->get_prev_effect(2), _("Interpolate Pixels")) &&
636                 !strcmp(get_output()->get_prev_effect(1), _("Gamma")) &&
637                 !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
638         {
639                 aggregate_interpolation = 1;
640                 aggregate_gamma = 1;
641                 aggregate_colorbalance = 1;
642         }
643         else
644         if(!strcmp(get_output()->get_prev_effect(1), _("Gamma")) &&
645                 !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
646         {
647                 aggregate_gamma = 1;
648                 aggregate_colorbalance = 1;
649         }
650         else
651         if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
652                 !strcmp(get_output()->get_prev_effect(0), _("Gamma")))
653         {
654                 aggregate_interpolation = 1;
655                 aggregate_gamma = 1;
656         }
657         else
658         if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
659                 !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
660         {
661                 aggregate_interpolation = 1;
662                 aggregate_colorbalance = 1;
663         }
664         else
665         if(!strcmp(get_output()->get_prev_effect(0), _("Interpolate Pixels")))
666                 aggregate_interpolation = 1;
667         else
668         if(!strcmp(get_output()->get_prev_effect(0), _("Gamma")))
669                 aggregate_gamma = 1;
670         else
671         if(!strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
672                 aggregate_colorbalance = 1;
673
674
675 // The order of processing is fixed by this sequence
676         if(aggregate_interpolation)
677                 INTERPOLATE_COMPILE(shader_stack,
678                         current_shader)
679
680         if(aggregate_gamma)
681                 GAMMA_COMPILE(shader_stack,
682                         current_shader,
683                         aggregate_interpolation)
684
685         if(aggregate_colorbalance)
686                 COLORBALANCE_COMPILE(shader_stack,
687                         current_shader,
688                         aggregate_interpolation || aggregate_gamma)
689
690
691         if(aggregate_interpolation || aggregate_gamma || aggregate_colorbalance)
692                 shader_stack[current_shader++] = histogram_get_pixel1;
693         else
694                 shader_stack[current_shader++] = histogram_get_pixel2;
695
696         unsigned int shader = 0;
697         switch(get_output()->get_color_model())
698         {
699                 case BC_YUV888:
700                 case BC_YUVA8888:
701                         shader_stack[current_shader++] = head_frag;
702                         shader_stack[current_shader++] = get_yuv_frag;
703                         shader_stack[current_shader++] = apply_histogram_frag;
704                         shader_stack[current_shader++] = put_yuv_frag;
705                         break;
706                 default:
707                         shader_stack[current_shader++] = head_frag;
708                         shader_stack[current_shader++] = get_rgb_frag;
709                         shader_stack[current_shader++] = apply_histogram_frag;
710                         shader_stack[current_shader++] = put_rgb_frag;
711                         break;
712         }
713
714         shader = VFrame::make_shader(0,
715                 shader_stack[0],
716                 shader_stack[1],
717                 shader_stack[2],
718                 shader_stack[3],
719                 shader_stack[4],
720                 shader_stack[5],
721                 shader_stack[6],
722                 shader_stack[7],
723                 shader_stack[8],
724                 shader_stack[9],
725                 shader_stack[10],
726                 shader_stack[11],
727                 shader_stack[12],
728                 shader_stack[13],
729                 shader_stack[14],
730                 shader_stack[15],
731                 0);
732
733 // printf("HistogramMain::handle_opengl %d %d %d %d shader=%d\n",
734 // aggregate_interpolation,
735 // aggregate_gamma,
736 // aggregate_colorbalance,
737 // current_shader,
738 // shader);
739
740         float low_input[4];
741         float high_input[4];
742         float gamma[4];
743         float low_output[4];
744         float output_scale[4];
745
746
747 // printf("min x    min y    max x    max y\n");
748 // printf("%f %f %f %f\n", input_min_r[0], input_min_r[1], input_max_r[0], input_max_r[1]);
749 // printf("%f %f %f %f\n", input_min_g[0], input_min_g[1], input_max_g[0], input_max_g[1]);
750 // printf("%f %f %f %f\n", input_min_b[0], input_min_b[1], input_max_b[0], input_max_b[1]);
751 // printf("%f %f %f %f\n", input_min_v[0], input_min_v[1], input_max_v[0], input_max_v[1]);
752
753         for(int i = 0; i < HISTOGRAM_MODES; i++)
754         {
755                 low_input[i] = config.low_input[i];
756                 high_input[i] = config.high_input[i];
757                 gamma[i] = config.gamma[i];
758                 low_output[i] = config.low_output[i];
759                 output_scale[i] = config.high_output[i] - config.low_output[i];
760         }
761
762         if(shader > 0)
763         {
764                 glUseProgram(shader);
765                 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
766                 if(aggregate_gamma) GAMMA_UNIFORMS(shader)
767                 if(aggregate_interpolation) INTERPOLATE_UNIFORMS(shader)
768                 if(aggregate_colorbalance) COLORBALANCE_UNIFORMS(shader)
769                 glUniform4fv(glGetUniformLocation(shader, "low_input"), 1, low_input);
770                 glUniform4fv(glGetUniformLocation(shader, "high_input"), 1, high_input);
771                 glUniform4fv(glGetUniformLocation(shader, "gamma"), 1, gamma);
772                 glUniform4fv(glGetUniformLocation(shader, "low_output"), 1, low_output);
773                 glUniform4fv(glGetUniformLocation(shader, "output_scale"), 1, output_scale);
774         }
775
776         get_output()->init_screen();
777         get_output()->bind_texture(0);
778
779         glDisable(GL_BLEND);
780
781 // Draw the affected half
782         if(config.split)
783         {
784                 glBegin(GL_TRIANGLES);
785                 glNormal3f(0, 0, 1.0);
786
787                 glTexCoord2f(0.0 / get_output()->get_texture_w(),
788                         0.0 / get_output()->get_texture_h());
789                 glVertex3f(0.0, -(float)get_output()->get_h(), 0);
790
791
792                 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
793                         (float)get_output()->get_h() / get_output()->get_texture_h());
794                 glVertex3f((float)get_output()->get_w(), -0.0, 0);
795
796                 glTexCoord2f(0.0 / get_output()->get_texture_w(),
797                         (float)get_output()->get_h() / get_output()->get_texture_h());
798                 glVertex3f(0.0, -0.0, 0);
799
800
801                 glEnd();
802         }
803         else
804         {
805                 get_output()->draw_texture();
806         }
807
808         glUseProgram(0);
809
810 // Draw the unaffected half
811         if(config.split)
812         {
813                 glBegin(GL_TRIANGLES);
814                 glNormal3f(0, 0, 1.0);
815
816
817                 glTexCoord2f(0.0 / get_output()->get_texture_w(),
818                         0.0 / get_output()->get_texture_h());
819                 glVertex3f(0.0, -(float)get_output()->get_h(), 0);
820
821                 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
822                         0.0 / get_output()->get_texture_h());
823                 glVertex3f((float)get_output()->get_w(),
824                         -(float)get_output()->get_h(), 0);
825
826                 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
827                         (float)get_output()->get_h() / get_output()->get_texture_h());
828                 glVertex3f((float)get_output()->get_w(), -0.0, 0);
829
830
831                 glEnd();
832         }
833
834         get_output()->set_opengl_state(VFrame::SCREEN);
835 #endif
836         return 0;
837 }
838
839
840
841
842
843
844
845
846
847
848
849
850 HistogramPackage::HistogramPackage()
851  : LoadPackage()
852 {
853 }
854
855
856
857
858 HistogramUnit::HistogramUnit(HistogramEngine *server,
859         HistogramMain *plugin)
860  : LoadClient(server)
861 {
862         this->plugin = plugin;
863         this->server = server;
864         for(int i = 0; i < HISTOGRAM_MODES; i++)
865                 accum[i] = new int[HISTOGRAM_SLOTS];
866 }
867
868 HistogramUnit::~HistogramUnit()
869 {
870         for(int i = 0; i < HISTOGRAM_MODES; i++)
871                 delete [] accum[i];
872 }
873
874 void HistogramUnit::process_package(LoadPackage *package)
875 {
876         HistogramPackage *pkg = (HistogramPackage*)package;
877
878         if(server->operation == HistogramEngine::HISTOGRAM)
879         {
880                 int do_value = server->do_value;
881
882
883 #define HISTOGRAM_HEAD(type) \
884 { \
885         for(int i = pkg->start; i < pkg->end; i++) \
886         { \
887                 type *row = (type*)data->get_rows()[i]; \
888                 for(int j = 0; j < w; j++) \
889                 {
890
891 #define HISTOGRAM_TAIL(components) \
892 /* Value takes the maximum of the output RGB values */ \
893                         if(do_value) \
894                         { \
895                                 CLAMP(r, 0, HISTOGRAM_SLOTS - 1); \
896                                 CLAMP(g, 0, HISTOGRAM_SLOTS - 1); \
897                                 CLAMP(b, 0, HISTOGRAM_SLOTS - 1); \
898                                 r_out = lookup_r[r]; \
899                                 g_out = lookup_g[g]; \
900                                 b_out = lookup_b[b]; \
901 /*                              v = (r * 76 + g * 150 + b * 29) >> 8; */ \
902                                 v = MAX(r_out, g_out); \
903                                 v = MAX(v, b_out); \
904                                 v += -HISTOGRAM_MIN * 0xffff / 100; \
905                                 CLAMP(v, 0, HISTOGRAM_SLOTS - 1); \
906                                 accum_v[v]++; \
907                         } \
908  \
909                         r += -HISTOGRAM_MIN * 0xffff / 100; \
910                         g += -HISTOGRAM_MIN * 0xffff / 100; \
911                         b += -HISTOGRAM_MIN * 0xffff / 100; \
912                         CLAMP(r, 0, HISTOGRAM_SLOTS - 1); \
913                         CLAMP(g, 0, HISTOGRAM_SLOTS - 1); \
914                         CLAMP(b, 0, HISTOGRAM_SLOTS - 1); \
915                         accum_r[r]++; \
916                         accum_g[g]++; \
917                         accum_b[b]++; \
918                         row += components; \
919                 } \
920         } \
921 }
922
923
924
925
926                 VFrame *data = server->data;
927                 int w = data->get_w();
928                 //int h = data->get_h();
929                 int *accum_r = accum[HISTOGRAM_RED];
930                 int *accum_g = accum[HISTOGRAM_GREEN];
931                 int *accum_b = accum[HISTOGRAM_BLUE];
932                 int *accum_v = accum[HISTOGRAM_VALUE];
933                 int32_t r, g, b, y, u, v;
934                 int r_out, g_out, b_out;
935                 int *lookup_r = plugin->preview_lookup[HISTOGRAM_RED];
936                 int *lookup_g = plugin->preview_lookup[HISTOGRAM_GREEN];
937                 int *lookup_b = plugin->preview_lookup[HISTOGRAM_BLUE];
938
939                 switch(data->get_color_model())
940                 {
941                         case BC_RGB888:
942                                 HISTOGRAM_HEAD(unsigned char)
943                                 r = (row[0] << 8) | row[0];
944                                 g = (row[1] << 8) | row[1];
945                                 b = (row[2] << 8) | row[2];
946                                 HISTOGRAM_TAIL(3)
947                                 break;
948                         case BC_RGB_FLOAT:
949                                 HISTOGRAM_HEAD(float)
950                                 r = (int)(row[0] * 0xffff);
951                                 g = (int)(row[1] * 0xffff);
952                                 b = (int)(row[2] * 0xffff);
953                                 HISTOGRAM_TAIL(3)
954                                 break;
955                         case BC_YUV888:
956                                 HISTOGRAM_HEAD(unsigned char)
957                                 y = (row[0] << 8) | row[0];
958                                 u = (row[1] << 8) | row[1];
959                                 v = (row[2] << 8) | row[2];
960                                 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
961                                 HISTOGRAM_TAIL(3)
962                                 break;
963                         case BC_RGBA8888:
964                                 HISTOGRAM_HEAD(unsigned char)
965                                 r = (row[0] << 8) | row[0];
966                                 g = (row[1] << 8) | row[1];
967                                 b = (row[2] << 8) | row[2];
968                                 HISTOGRAM_TAIL(4)
969                                 break;
970                         case BC_RGBA_FLOAT:
971                                 HISTOGRAM_HEAD(float)
972                                 r = (int)(row[0] * 0xffff);
973                                 g = (int)(row[1] * 0xffff);
974                                 b = (int)(row[2] * 0xffff);
975                                 HISTOGRAM_TAIL(4)
976                                 break;
977                         case BC_YUVA8888:
978                                 HISTOGRAM_HEAD(unsigned char)
979                                 y = (row[0] << 8) | row[0];
980                                 u = (row[1] << 8) | row[1];
981                                 v = (row[2] << 8) | row[2];
982                                 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
983                                 HISTOGRAM_TAIL(4)
984                                 break;
985                         case BC_RGB161616:
986                                 HISTOGRAM_HEAD(uint16_t)
987                                 r = row[0];
988                                 g = row[1];
989                                 b = row[2];
990                                 HISTOGRAM_TAIL(3)
991                                 break;
992                         case BC_YUV161616:
993                                 HISTOGRAM_HEAD(uint16_t)
994                                 y = row[0];
995                                 u = row[1];
996                                 v = row[2];
997                                 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
998                                 HISTOGRAM_TAIL(3)
999                                 break;
1000                         case BC_RGBA16161616:
1001                                 HISTOGRAM_HEAD(uint16_t)
1002                                 r = row[0];
1003                                 g = row[1];
1004                                 b = row[2];
1005                                 HISTOGRAM_TAIL(3)
1006                                 break;
1007                         case BC_YUVA16161616:
1008                                 HISTOGRAM_HEAD(uint16_t)
1009                                 y = row[0];
1010                                 u = row[1];
1011                                 v = row[2];
1012                                 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1013                                 HISTOGRAM_TAIL(4)
1014                                 break;
1015                 }
1016         }
1017         else
1018         if(server->operation == HistogramEngine::APPLY)
1019         {
1020
1021
1022
1023 #define PROCESS(type, components) \
1024 { \
1025         for(int i = pkg->start; i < pkg->end; i++) \
1026         { \
1027                 type *row = (type*)input->get_rows()[i]; \
1028                 for(int j = 0; j < w; j++) \
1029                 { \
1030                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
1031                         continue; \
1032                         row[0] = lookup_r[row[0]]; \
1033                         row[1] = lookup_g[row[1]]; \
1034                         row[2] = lookup_b[row[2]]; \
1035                         row += components; \
1036                 } \
1037         } \
1038 }
1039
1040 #define PROCESS_YUV(type, components, max) \
1041 { \
1042         for(int i = pkg->start; i < pkg->end; i++) \
1043         { \
1044                 type *row = (type*)input->get_rows()[i]; \
1045                 for(int j = 0; j < w; j++) \
1046                 { \
1047                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
1048                         continue; \
1049 /* Convert to 16 bit RGB */ \
1050                         if(max == 0xff) \
1051                         { \
1052                                 y = (row[0] << 8) | row[0]; \
1053                                 u = (row[1] << 8) | row[1]; \
1054                                 v = (row[2] << 8) | row[2]; \
1055                         } \
1056                         else \
1057                         { \
1058                                 y = row[0]; \
1059                                 u = row[1]; \
1060                                 v = row[2]; \
1061                         } \
1062  \
1063                         YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
1064  \
1065 /* Look up in RGB domain */ \
1066                         r = lookup_r[r]; \
1067                         g = lookup_g[g]; \
1068                         b = lookup_b[b]; \
1069  \
1070 /* Convert to 16 bit YUV */ \
1071                         YUV::yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
1072  \
1073                         if(max == 0xff) \
1074                         { \
1075                                 row[0] = y >> 8; \
1076                                 row[1] = u >> 8; \
1077                                 row[2] = v >> 8; \
1078                         } \
1079                         else \
1080                         { \
1081                                 row[0] = y; \
1082                                 row[1] = u; \
1083                                 row[2] = v; \
1084                         } \
1085                         row += components; \
1086                 } \
1087         } \
1088 }
1089
1090 #define PROCESS_FLOAT(components) \
1091 { \
1092         for(int i = pkg->start; i < pkg->end; i++) \
1093         { \
1094                 float *row = (float*)input->get_rows()[i]; \
1095                 for(int j = 0; j < w; j++) \
1096                 { \
1097                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
1098                         continue; \
1099                         float r = row[0]; \
1100                         float g = row[1]; \
1101                         float b = row[2]; \
1102  \
1103                         r = plugin->calculate_level(r, HISTOGRAM_RED, 1); \
1104                         g = plugin->calculate_level(g, HISTOGRAM_GREEN, 1); \
1105                         b = plugin->calculate_level(b, HISTOGRAM_BLUE, 1); \
1106  \
1107                         row[0] = r; \
1108                         row[1] = g; \
1109                         row[2] = b; \
1110  \
1111                         row += components; \
1112                 } \
1113         } \
1114 }
1115
1116
1117                 VFrame *input = plugin->input;
1118                 //VFrame *output = plugin->output;
1119                 int w = input->get_w();
1120                 int h = input->get_h();
1121                 int *lookup_r = plugin->lookup[0];
1122                 int *lookup_g = plugin->lookup[1];
1123                 int *lookup_b = plugin->lookup[2];
1124                 int r, g, b, y, u, v;
1125                 switch(input->get_color_model())
1126                 {
1127                         case BC_RGB888:
1128                                 PROCESS(unsigned char, 3)
1129                                 break;
1130                         case BC_RGB_FLOAT:
1131                                 PROCESS_FLOAT(3);
1132                                 break;
1133                         case BC_RGBA8888:
1134                                 PROCESS(unsigned char, 4)
1135                                 break;
1136                         case BC_RGBA_FLOAT:
1137                                 PROCESS_FLOAT(4);
1138                                 break;
1139                         case BC_RGB161616:
1140                                 PROCESS(uint16_t, 3)
1141                                 break;
1142                         case BC_RGBA16161616:
1143                                 PROCESS(uint16_t, 4)
1144                                 break;
1145                         case BC_YUV888:
1146                                 PROCESS_YUV(unsigned char, 3, 0xff)
1147                                 break;
1148                         case BC_YUVA8888:
1149                                 PROCESS_YUV(unsigned char, 4, 0xff)
1150                                 break;
1151                         case BC_YUV161616:
1152                                 PROCESS_YUV(uint16_t, 3, 0xffff)
1153                                 break;
1154                         case BC_YUVA16161616:
1155                                 PROCESS_YUV(uint16_t, 4, 0xffff)
1156                                 break;
1157                 }
1158         }
1159 }
1160
1161
1162
1163
1164
1165
1166 HistogramEngine::HistogramEngine(HistogramMain *plugin,
1167         int total_clients,
1168         int total_packages)
1169  : LoadServer(total_clients, total_packages)
1170 {
1171         this->plugin = plugin;
1172 }
1173
1174 void HistogramEngine::init_packages()
1175 {
1176         switch(operation)
1177         {
1178                 case HISTOGRAM:
1179                         total_size = data->get_h();
1180                         break;
1181                 case APPLY:
1182                         total_size = data->get_h();
1183                         break;
1184         }
1185
1186
1187         //int package_size = (int)((float)total_size / get_total_packages() + 1);
1188         //int start = 0;
1189
1190         for(int i = 0; i < get_total_packages(); i++)
1191         {
1192                 HistogramPackage *package = (HistogramPackage*)get_package(i);
1193                 package->start = total_size * i / get_total_packages();
1194                 package->end = total_size * (i + 1) / get_total_packages();
1195         }
1196
1197 // Initialize clients here in case some don't get run.
1198         for(int i = 0; i < get_total_clients(); i++)
1199         {
1200                 HistogramUnit *unit = (HistogramUnit*)get_client(i);
1201                 for(int i = 0; i < HISTOGRAM_MODES; i++)
1202                         bzero(unit->accum[i], sizeof(int) * HISTOGRAM_SLOTS);
1203         }
1204
1205 }
1206
1207 LoadClient* HistogramEngine::new_client()
1208 {
1209         return new HistogramUnit(this, plugin);
1210 }
1211
1212 LoadPackage* HistogramEngine::new_package()
1213 {
1214         return new HistogramPackage;
1215 }
1216
1217 void HistogramEngine::process_packages(int operation, VFrame *data, int do_value)
1218 {
1219         this->data = data;
1220         this->operation = operation;
1221         this->do_value = do_value;
1222         LoadServer::process_packages();
1223 }
1224
1225