Fixed initialisation of tf in file_open(). Without setting the memory to 0,
[cinelerra_cv/mob.git] / plugins / histogram / histogram.C
blob3b7fdee0686e3c80a3f0b9d871b6dca5504ada09
1 #include <math.h>
2 #include <stdint.h>
3 #include <string.h>
4 #include <unistd.h>
6 #include "bcdisplayinfo.h"
7 #include "bcsignals.h"
8 #include "clip.h"
9 #include "bchash.h"
10 #include "filexml.h"
11 #include "histogram.h"
12 #include "histogramconfig.h"
13 #include "histogramwindow.h"
14 #include "keyframe.h"
15 #include "language.h"
16 #include "loadbalance.h"
17 #include "playback3d.h"
18 #include "plugincolors.h"
19 #include "vframe.h"
20 #include "workarounds.h"
22 #include "aggregated.h"
23 #include "../colorbalance/aggregated.h"
24 #include "../interpolate/aggregated.h"
25 #include "../gamma/aggregated.h"
27 class HistogramMain;
28 class HistogramEngine;
29 class HistogramWindow;
35 REGISTER_PLUGIN(HistogramMain)
48 HistogramMain::HistogramMain(PluginServer *server)
49  : PluginVClient(server)
51         PLUGIN_CONSTRUCTOR_MACRO
52         engine = 0;
53         for(int i = 0; i < HISTOGRAM_MODES; i++)
54         {
55                 lookup[i] = 0;
56                 smoothed[i] = 0;
57                 linear[i] = 0;
58                 accum[i] = 0;
59                 preview_lookup[i] = 0;
60         }
61         current_point = -1;
62         mode = HISTOGRAM_VALUE;
63         dragging_point = 0;
64         input = 0;
65         output = 0;
68 HistogramMain::~HistogramMain()
70         PLUGIN_DESTRUCTOR_MACRO
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                 delete [] preview_lookup[i];
78         }
79         delete engine;
82 char* HistogramMain::plugin_title() { return N_("Histogram"); }
83 int HistogramMain::is_realtime() { return 1; }
86 #include "picon_png.h"
87 NEW_PICON_MACRO(HistogramMain)
89 SHOW_GUI_MACRO(HistogramMain, HistogramThread)
91 SET_STRING_MACRO(HistogramMain)
93 RAISE_WINDOW_MACRO(HistogramMain)
95 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
97 void HistogramMain::render_gui(void *data)
99         if(thread)
100         {
101 SET_TRACE
102 // Process just the RGB values to determine the automatic points or
103 // all the points if manual
104                 if(!config.automatic)
105                 {
106 // Generate curves for value histogram
107 // Lock out changes to curves
108                         thread->window->lock_window("HistogramMain::render_gui 1");
109                         tabulate_curve(HISTOGRAM_RED, 0);
110                         tabulate_curve(HISTOGRAM_GREEN, 0);
111                         tabulate_curve(HISTOGRAM_BLUE, 0);
112                         thread->window->unlock_window();
113                 }
115                 calculate_histogram((VFrame*)data, !config.automatic);
117 SET_TRACE
119                 if(config.automatic)
120                 {
121 SET_TRACE
122                         calculate_automatic((VFrame*)data);
124 SET_TRACE
125 // Generate curves for value histogram
126 // Lock out changes to curves
127                         thread->window->lock_window("HistogramMain::render_gui 1");
128                         tabulate_curve(HISTOGRAM_RED, 0);
129                         tabulate_curve(HISTOGRAM_GREEN, 0);
130                         tabulate_curve(HISTOGRAM_BLUE, 0);
131                         thread->window->unlock_window();
133 SET_TRACE
134 // Need a second pass to get the luminance values.
135                         calculate_histogram((VFrame*)data, 1);
136 SET_TRACE
137                 }
139 SET_TRACE
140                 thread->window->lock_window("HistogramMain::render_gui 2");
141                 thread->window->update_canvas();
142                 if(config.automatic)
143                 {
144                         thread->window->update_input();
145                 }
146                 thread->window->unlock_window();
147 SET_TRACE
148         }
151 void HistogramMain::update_gui()
153         if(thread)
154         {
155                 thread->window->lock_window("HistogramMain::update_gui");
156                 int reconfigure = load_configuration();
157                 if(reconfigure) 
158                 {
159                         thread->window->update(0);
160                         if(!config.automatic)
161                         {
162                                 thread->window->update_input();
163                         }
164                 }
165                 thread->window->unlock_window();
166         }
170 int HistogramMain::load_defaults()
172         char directory[BCTEXTLEN], string[BCTEXTLEN];
173 // set the default directory
174         sprintf(directory, "%shistogram.rc", BCASTDIR);
176 // load the defaults
177         defaults = new BC_Hash(directory);
178         defaults->load();
180         for(int j = 0; j < HISTOGRAM_MODES; j++)
181         {
182                 while(config.points[j].last) delete config.points[j].last;
184                 sprintf(string, "TOTAL_POINTS_%d", j);
185                 int total_points = defaults->get(string, 0);
187                 for(int i = 0; i < total_points; i++)
188                 {
189                         HistogramPoint *point = new HistogramPoint;
190                         sprintf(string, "INPUT_X_%d_%d", j, i);
191                         point->x = defaults->get(string, point->x);
192                         sprintf(string, "INPUT_Y_%d_%d", j, i);
193                         point->y = defaults->get(string, point->y);
194                         config.points[j].append(point);
195                 }
196         }
199         for(int i = 0; i < HISTOGRAM_MODES; i++)
200         {
201                 sprintf(string, "OUTPUT_MIN_%d", i);
202                 config.output_min[i] = defaults->get(string, config.output_min[i]);
203                 sprintf(string, "OUTPUT_MAX_%d", i);
204                 config.output_max[i] = defaults->get(string, config.output_max[i]);
205         }
207         config.automatic = defaults->get("AUTOMATIC", config.automatic);
208         mode = defaults->get("MODE", mode);
209         CLAMP(mode, 0, HISTOGRAM_MODES - 1);
210         config.threshold = defaults->get("THRESHOLD", config.threshold);
211         config.plot = defaults->get("PLOT", config.plot);
212         config.split = defaults->get("SPLIT", config.split);
213         config.boundaries();
214         return 0;
218 int HistogramMain::save_defaults()
220         char string[BCTEXTLEN];
224         for(int j = 0; j < HISTOGRAM_MODES; j++)
225         {
226                 int total_points = config.points[j].total();
227                 sprintf(string, "TOTAL_POINTS_%d", j);
228                 defaults->update(string, total_points);
229                 HistogramPoint *current = config.points[j].first;
230                 int number = 0;
231                 while(current)
232                 {
233                         sprintf(string, "INPUT_X_%d_%d", j, number);
234                         defaults->update(string, current->x);
235                         sprintf(string, "INPUT_Y_%d_%d", j, number);
236                         defaults->update(string, current->y);
237                         current = NEXT;
238                         number++;
239                 }
240         }
243         for(int i = 0; i < HISTOGRAM_MODES; i++)
244         {
245                 sprintf(string, "OUTPUT_MIN_%d", i);
246                 defaults->update(string, config.output_min[i]);
247                 sprintf(string, "OUTPUT_MAX_%d", i);
248                 defaults->update(string, config.output_max[i]);
249         }
251         defaults->update("AUTOMATIC", config.automatic);
252         defaults->update("MODE", mode);
253         defaults->update("THRESHOLD", config.threshold);
254         defaults->update("PLOT", config.plot);
255         defaults->update("SPLIT", config.split);
256         defaults->save();
257         return 0;
262 void HistogramMain::save_data(KeyFrame *keyframe)
264         FileXML output;
266 // cause data to be stored directly in text
267         output.set_shared_string(keyframe->data, MESSAGESIZE);
268         output.tag.set_title("HISTOGRAM");
270         char string[BCTEXTLEN];
273         for(int i = 0; i < HISTOGRAM_MODES; i++)
274         {
275                 sprintf(string, "OUTPUT_MIN_%d", i);
276                 output.tag.set_property(string, config.output_min[i]);
277                 sprintf(string, "OUTPUT_MAX_%d", i);
278                 output.tag.set_property(string, config.output_max[i]);
279 //printf("HistogramMain::save_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
280         }
282         output.tag.set_property("AUTOMATIC", config.automatic);
283         output.tag.set_property("THRESHOLD", config.threshold);
284         output.tag.set_property("PLOT", config.plot);
285         output.tag.set_property("SPLIT", config.split);
286         output.append_tag();
287         output.append_newline();
293         for(int j = 0; j < HISTOGRAM_MODES; j++)
294         {
295                 output.tag.set_title("POINTS");
296                 output.append_tag();
297                 output.append_newline();
300                 HistogramPoint *current = config.points[j].first;
301                 while(current)
302                 {
303                         output.tag.set_title("POINT");
304                         output.tag.set_property("X", current->x);
305                         output.tag.set_property("Y", current->y);
306                         output.append_tag();
307                         output.append_newline();
308                         current = NEXT;
309                 }
312                 output.tag.set_title("/POINTS");
313                 output.append_tag();
314                 output.append_newline();
315         }
322         output.terminate_string();
325 void HistogramMain::read_data(KeyFrame *keyframe)
327         FileXML input;
329         input.set_shared_string(keyframe->data, strlen(keyframe->data));
331         int result = 0;
332         int current_input_mode = 0;
335         while(!result)
336         {
337                 result = input.read_tag();
339                 if(!result)
340                 {
341                         if(input.tag.title_is("HISTOGRAM"))
342                         {
343                                 char string[BCTEXTLEN];
344                                 for(int i = 0; i < HISTOGRAM_MODES; i++)
345                                 {
346                                         sprintf(string, "OUTPUT_MIN_%d", i);
347                                         config.output_min[i] = input.tag.get_property(string, config.output_min[i]);
348                                         sprintf(string, "OUTPUT_MAX_%d", i);
349                                         config.output_max[i] = input.tag.get_property(string, config.output_max[i]);
350 //printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
351                                 }
352                                 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
353                                 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
354                                 config.plot = input.tag.get_property("PLOT", config.plot);
355                                 config.split = input.tag.get_property("SPLIT", config.split);
356                         }
357                         else
358                         if(input.tag.title_is("POINTS"))
359                         {
360                                 if(current_input_mode < HISTOGRAM_MODES)
361                                 {
362                                         HistogramPoints *points = &config.points[current_input_mode];
363                                         while(points->last) 
364                                                 delete points->last;
365                                         while(!result)
366                                         {
367                                                 result = input.read_tag();
368                                                 if(!result)
369                                                 {
370                                                         if(input.tag.title_is("/POINTS"))
371                                                         {
372                                                                 break;
373                                                         }
374                                                         else
375                                                         if(input.tag.title_is("POINT"))
376                                                         {
377                                                                 points->insert(
378                                                                         input.tag.get_property("X", 0.0),
379                                                                         input.tag.get_property("Y", 0.0));
380                                                         }
381                                                 }
382                                         }
384                                 }
385                                 current_input_mode++;
386                         }
387                 }
388         }
390         config.boundaries();
394 float HistogramMain::calculate_linear(float input, 
395         int subscript,
396         int use_value)
398         int done = 0;
399         float output;
401 //      if(input < 0)
402 //      {
403 //              output = 0;
404 //              done = 1;
405 //      }
406 // 
407 //      if(input > 1)
408 //      {
409 //              output = 1;
410 //              done = 1;
411 //      }
413         if(!done)
414         {
416                 float x1 = 0;
417                 float y1 = 0;
418                 float x2 = 1;
419                 float y2 = 1;
423 // Get 2 points surrounding current position
424                 HistogramPoints *points = &config.points[subscript];
425                 HistogramPoint *current = points->first;
426                 int done = 0;
427                 while(current && !done)
428                 {
429                         if(current->x > input)
430                         {
431                                 x2 = current->x;
432                                 y2 = current->y;
433                                 done = 1;
434                         }
435                         else
436                                 current = NEXT;
437                 }
439                 current = points->last;
440                 done = 0;
441                 while(current && !done)
442                 {
443                         if(current->x <= input)
444                         {
445                                 x1 = current->x;
446                                 y1 = current->y;
447                                 done = 1;
448                         }
449                         else
450                                 current = PREVIOUS;
451                 }
456 // Linear
457                 if(!EQUIV(x2 - x1, 0))
458                         output = (input - x1) * (y2 - y1) / (x2 - x1) + y1;
459                 else
460                         output = input * y2;
466         }
468 // Apply value curve
469         if(use_value)
470         {
471                 output = calculate_linear(output, HISTOGRAM_VALUE, 0);
472         }
475         float output_min = config.output_min[subscript];
476         float output_max = config.output_max[subscript];
477         float output_left;
478         float output_right;
479         float output_linear;
481 // Compress output for value followed by channel
482         output = output_min + 
483                 output * 
484                 (output_max - output_min);
487         return output;
490 float HistogramMain::calculate_smooth(float input, int subscript)
492         float x_f = (input - MIN_INPUT) * HISTOGRAM_SLOTS / FLOAT_RANGE;
493         int x_i1 = (int)x_f;
494         int x_i2 = x_i1 + 1;
495         CLAMP(x_i1, 0, HISTOGRAM_SLOTS - 1);
496         CLAMP(x_i2, 0, HISTOGRAM_SLOTS - 1);
497         CLAMP(x_f, 0, HISTOGRAM_SLOTS - 1);
499         float smooth1 = smoothed[subscript][x_i1];
500         float smooth2 = smoothed[subscript][x_i2];
501         float result = smooth1 + (smooth2 - smooth1) * (x_f - x_i1);
502         CLAMP(result, 0, 1.0);
503         return result;
507 void HistogramMain::calculate_histogram(VFrame *data, int do_value)
510         if(!engine) engine = new HistogramEngine(this,
511                 get_project_smp() + 1,
512                 get_project_smp() + 1);
514         if(!accum[0])
515         {
516                 for(int i = 0; i < HISTOGRAM_MODES; i++)
517                         accum[i] = new int[HISTOGRAM_SLOTS];
518         }
520         engine->process_packages(HistogramEngine::HISTOGRAM, data, do_value);
522         for(int i = 0; i < engine->get_total_clients(); i++)
523         {
524                 HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
526                 if(i == 0)
527                 {
528                         for(int j = 0; j < HISTOGRAM_MODES; j++)
529                         {
530                                 memcpy(accum[j], unit->accum[j], sizeof(int) * HISTOGRAM_SLOTS);
531                         }
532                 }
533                 else
534                 {
535                         for(int j = 0; j < HISTOGRAM_MODES; j++)
536                         {
537                                 int *out = accum[j];
538                                 int *in = unit->accum[j];
539                                 for(int k = 0; k < HISTOGRAM_SLOTS; k++)
540                                         out[k] += in[k];
541                         }
542                 }
543         }
545 // Remove top and bottom from calculations.  Doesn't work in high
546 // precision colormodels.
547         for(int i = 0; i < HISTOGRAM_MODES; i++)
548         {
549                 accum[i][0] = 0;
550                 accum[i][HISTOGRAM_SLOTS - 1] = 0;
551         }
555 void HistogramMain::calculate_automatic(VFrame *data)
557         calculate_histogram(data, 0);
558         config.reset_points(1);
560 // Do each channel
561         for(int i = 0; i < 3; i++)
562         {
563                 int *accum = this->accum[i];
564                 int pixels = data->get_w() * data->get_h();
565                 float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
566                 int threshold = (int)(white_fraction * pixels);
567                 int total = 0;
568                 float max_level = 1.0;
569                 float min_level = 0.0;
571 // Get histogram slot above threshold of pixels
572                 for(int j = 0; j < HISTOGRAM_SLOTS; j++)
573                 {
574                         total += accum[j];
575                         if(total >= threshold)
576                         {
577                                 max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
578                                 break;
579                         }
580                 }
582 // Get slot below 99% of pixels
583                 total = 0;
584                 for(int j = HISTOGRAM_SLOTS - 1; j >= 0; j--)
585                 {
586                         total += accum[j];
587                         if(total >= threshold)
588                         {
589                                 min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
590                                 break;
591                         }
592                 }
595                 config.points[i].insert(max_level, 1.0);
596                 config.points[i].insert(min_level, 0.0);
597         }
604 int HistogramMain::calculate_use_opengl()
606 // glHistogram doesn't work.
607         int result = get_use_opengl() &&
608                 !config.automatic && 
609                 config.points[HISTOGRAM_RED].total() < 3 &&
610                 config.points[HISTOGRAM_GREEN].total() < 3 &&
611                 config.points[HISTOGRAM_BLUE].total() < 3 &&
612                 config.points[HISTOGRAM_VALUE].total() < 3 &&
613                 (!config.plot || !gui_open());
614         return result;
618 int HistogramMain::process_buffer(VFrame *frame,
619         int64_t start_position,
620         double frame_rate)
622 SET_TRACE
623         int need_reconfigure = load_configuration();
626 SET_TRACE
627         int use_opengl = calculate_use_opengl();
629 //printf("%d\n", use_opengl);
630         read_frame(frame, 
631                 0, 
632                 start_position, 
633                 frame_rate,
634                 use_opengl);
636 // Apply histogram in hardware
637         if(use_opengl) return run_opengl();
639         if(!engine) engine = new HistogramEngine(this,
640                 get_project_smp() + 1,
641                 get_project_smp() + 1);
642         this->input = frame;
643         this->output = frame;
645 // Always plot to set the curves if automatic
646         if(config.plot || config.automatic) send_render_gui(frame);
648 SET_TRACE
649 // Generate tables here.  The same table is used by many packages to render
650 // each horizontal stripe.  Need to cover the entire output range in  each
651 // table to avoid green borders
652         if(need_reconfigure || 
653                 !lookup[0] || 
654                 !smoothed[0] || 
655                 !linear[0] || 
656                 config.automatic)
657         {
658 SET_TRACE
659 // Calculate new curves
660                 if(config.automatic)
661                 {
662                         calculate_automatic(input);
663                 }
664 SET_TRACE
666 // Generate transfer tables with value function for integer colormodels.
667                 for(int i = 0; i < 3; i++)
668                         tabulate_curve(i, 1);
669 SET_TRACE
670         }
674 // Apply histogram
675         engine->process_packages(HistogramEngine::APPLY, input, 0);
677 SET_TRACE
679         return 0;
682 void HistogramMain::tabulate_curve(int subscript, int use_value)
684         int i;
685         if(!lookup[subscript])
686                 lookup[subscript] = new int[HISTOGRAM_SLOTS];
687         if(!smoothed[subscript])
688                 smoothed[subscript] = new float[HISTOGRAM_SLOTS];
689         if(!linear[subscript])
690                 linear[subscript] = new float[HISTOGRAM_SLOTS];
691         if(!preview_lookup[subscript])
692                 preview_lookup[subscript] = new int[HISTOGRAM_SLOTS];
695         float *current_smooth = smoothed[subscript];
696         float *current_linear = linear[subscript];
698 // Make linear curve
699         for(i = 0; i < HISTOGRAM_SLOTS; i++)
700         {
701                 float input = (float)i / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
702                 current_linear[i] = calculate_linear(input, subscript, use_value);
703         }
710 // Make smooth curve (currently a copy of the linear curve)
711         float prev = 0.0;
712         for(i = 0; i < HISTOGRAM_SLOTS; i++)
713         {
714 //              current_smooth[i] = current_linear[i] * 0.001 +
715 //                      prev * 0.999;
716 //              prev = current_smooth[i];
718                 current_smooth[i] = current_linear[i];
719         }
721 // Generate lookup tables for integer colormodels
722         if(input)
723         {
724                 switch(input->get_color_model())
725                 {
726                         case BC_RGB888:
727                         case BC_RGBA8888:
728                                 for(i = 0; i < 0x100; i++)
729                                         lookup[subscript][i] = 
730                                                 (int)(calculate_smooth((float)i / 0xff, subscript) * 0xff);
731                                 break;
732 // All other integer colormodels are converted to 16 bit RGB
733                         default:
734                                 for(i = 0; i < 0x10000; i++)
735                                         lookup[subscript][i] = 
736                                                 (int)(calculate_smooth((float)i / 0xffff, subscript) * 0xffff);
737                                 break;
738                 }
739         }
741 // Lookup table for preview only used for GUI
742         if(!use_value)
743         {
744                 for(i = 0; i < 0x10000; i++)
745                         preview_lookup[subscript][i] = 
746                                 (int)(calculate_smooth((float)i / 0xffff, subscript) * 0xffff);
747         }
750 int HistogramMain::handle_opengl()
752 #ifdef HAVE_GL
753 // Functions to get pixel from either previous effect or texture
754         static char *histogram_get_pixel1 =
755                 "vec4 histogram_get_pixel()\n"
756                 "{\n"
757                 "       return gl_FragColor;\n"
758                 "}\n";
760         static char *histogram_get_pixel2 =
761                 "uniform sampler2D tex;\n"
762                 "vec4 histogram_get_pixel()\n"
763                 "{\n"
764                 "       return texture2D(tex, gl_TexCoord[0].st);\n"
765                 "}\n";
767         static char *head_frag = 
768                 "// first input point\n"
769                 "uniform vec2 input_min_r;\n"
770                 "uniform vec2 input_min_g;\n"
771                 "uniform vec2 input_min_b;\n"
772                 "uniform vec2 input_min_v;\n"
773                 "// second input point\n"
774                 "uniform vec2 input_max_r;\n"
775                 "uniform vec2 input_max_g;\n"
776                 "uniform vec2 input_max_b;\n"
777                 "uniform vec2 input_max_v;\n"
778                 "// output points\n"
779                 "uniform vec4 output_min;\n"
780                 "uniform vec4 output_scale;\n"
781                 "void main()\n"
782                 "{\n";
784         static char *get_rgb_frag =
785                 "       vec4 pixel = histogram_get_pixel();\n";
787         static char *get_yuv_frag =
788                 "       vec4 pixel = histogram_get_pixel();\n"
789                         YUV_TO_RGB_FRAG("pixel");
791 #define APPLY_INPUT_CURVE(PIXEL, INPUT_MIN, INPUT_MAX) \
792                 "// apply input curve\n" \
793                 "       if(" PIXEL " < 0.0)\n" \
794                 "               " PIXEL " = 0.0;\n" \
795                 "       else\n" \
796                 "       if(" PIXEL " < " INPUT_MIN ".x)\n" \
797                 "               " PIXEL " = " PIXEL " * " INPUT_MIN ".y / " INPUT_MIN ".x;\n" \
798                 "       else\n" \
799                 "       if(" PIXEL " < " INPUT_MAX ".x)\n" \
800                 "               " PIXEL " = (" PIXEL " - " INPUT_MIN ".x) * \n" \
801                 "                       (" INPUT_MAX ".y - " INPUT_MIN ".y) / \n" \
802                 "                       (" INPUT_MAX ".x - " INPUT_MIN ".x) + \n" \
803                 "                       " INPUT_MIN ".y;\n" \
804                 "       else\n" \
805                 "       if(" PIXEL " < 1.0)\n" \
806                 "               " PIXEL " = (" PIXEL " - " INPUT_MAX ".x) * \n" \
807                 "                       (1.0 - " INPUT_MAX ".y) / \n" \
808                 "                       (1.0 - " INPUT_MAX ".x) + \n" \
809                 "                       " INPUT_MAX ".y;\n" \
810                 "       else\n" \
811                 "               " PIXEL " = 1.0;\n"
815         static char *apply_histogram_frag = 
816                 APPLY_INPUT_CURVE("pixel.r", "input_min_r", "input_max_r")
817                 APPLY_INPUT_CURVE("pixel.g", "input_min_g", "input_max_g")
818                 APPLY_INPUT_CURVE("pixel.b", "input_min_b", "input_max_b")
819                 "// apply output curve\n"
820                 "       pixel.rgb *= output_scale.rgb;\n"
821                 "       pixel.rgb += output_min.rgb;\n"
822                 APPLY_INPUT_CURVE("pixel.r", "input_min_v", "input_max_v")
823                 APPLY_INPUT_CURVE("pixel.g", "input_min_v", "input_max_v")
824                 APPLY_INPUT_CURVE("pixel.b", "input_min_v", "input_max_v")
825                 "// apply output curve\n"
826                 "       pixel.rgb *= vec3(output_scale.a, output_scale.a, output_scale.a);\n"
827                 "       pixel.rgb += vec3(output_min.a, output_min.a, output_min.a);\n";
829         static char *put_rgb_frag =
830                 "       gl_FragColor = pixel;\n"
831                 "}\n";
833         static char *put_yuv_frag =
834                         RGB_TO_YUV_FRAG("pixel")
835                 "       gl_FragColor = pixel;\n"
836                 "}\n";
840         get_output()->to_texture();
841         get_output()->enable_opengl();
843         char *shader_stack[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
844         int current_shader = 0;
845         int aggregate_interpolation = 0;
846         int aggregate_gamma = 0;
847         int aggregate_colorbalance = 0;
848 // All aggregation possibilities must be accounted for because unsupported
849 // effects can get in between the aggregation members.
850         if(!strcmp(get_output()->get_prev_effect(2), "Interpolate Pixels") &&
851                 !strcmp(get_output()->get_prev_effect(1), "Gamma") &&
852                 !strcmp(get_output()->get_prev_effect(0), "Color Balance"))
853         {
854                 aggregate_interpolation = 1;
855                 aggregate_gamma = 1;
856                 aggregate_colorbalance = 1;
857         }
858         else
859         if(!strcmp(get_output()->get_prev_effect(1), "Gamma") &&
860                 !strcmp(get_output()->get_prev_effect(0), "Color Balance"))
861         {
862                 aggregate_gamma = 1;
863                 aggregate_colorbalance = 1;
864         }
865         else
866         if(!strcmp(get_output()->get_prev_effect(1), "Interpolate Pixels") &&
867                 !strcmp(get_output()->get_prev_effect(0), "Gamma"))
868         {
869                 aggregate_interpolation = 1;
870                 aggregate_gamma = 1;
871         }
872         else
873         if(!strcmp(get_output()->get_prev_effect(1), "Interpolate Pixels") &&
874                 !strcmp(get_output()->get_prev_effect(0), "Color Balance"))
875         {
876                 aggregate_interpolation = 1;
877                 aggregate_colorbalance = 1;
878         }
879         else
880         if(!strcmp(get_output()->get_prev_effect(0), "Interpolate Pixels"))
881                 aggregate_interpolation = 1;
882         else
883         if(!strcmp(get_output()->get_prev_effect(0), "Gamma"))
884                 aggregate_gamma = 1;
885         else
886         if(!strcmp(get_output()->get_prev_effect(0), "Color Balance"))
887                 aggregate_colorbalance = 1;
890 // The order of processing is fixed by this sequence
891         if(aggregate_interpolation)
892                 INTERPOLATE_COMPILE(shader_stack, 
893                         current_shader)
895         if(aggregate_gamma)
896                 GAMMA_COMPILE(shader_stack, 
897                         current_shader, 
898                         aggregate_interpolation)
900         if(aggregate_colorbalance)
901                 COLORBALANCE_COMPILE(shader_stack, 
902                         current_shader, 
903                         aggregate_interpolation || aggregate_gamma)
906         if(aggregate_interpolation || aggregate_gamma || aggregate_colorbalance)
907                 shader_stack[current_shader++] = histogram_get_pixel1;
908         else
909                 shader_stack[current_shader++] = histogram_get_pixel2;
911         unsigned int shader = 0;
912         switch(get_output()->get_color_model())
913         {
914                 case BC_YUV888:
915                 case BC_YUVA8888:
916                         shader_stack[current_shader++] = head_frag;
917                         shader_stack[current_shader++] = get_yuv_frag;
918                         shader_stack[current_shader++] = apply_histogram_frag;
919                         shader_stack[current_shader++] = put_yuv_frag;
920                         break;
921                 default:
922                         shader_stack[current_shader++] = head_frag;
923                         shader_stack[current_shader++] = get_rgb_frag;
924                         shader_stack[current_shader++] = apply_histogram_frag;
925                         shader_stack[current_shader++] = put_rgb_frag;
926                         break;
927         }
929         shader = VFrame::make_shader(0,
930                 shader_stack[0],
931                 shader_stack[1],
932                 shader_stack[2],
933                 shader_stack[3],
934                 shader_stack[4],
935                 shader_stack[5],
936                 shader_stack[6],
937                 shader_stack[7],
938                 shader_stack[8],
939                 shader_stack[9],
940                 shader_stack[10],
941                 shader_stack[11],
942                 shader_stack[12],
943                 shader_stack[13],
944                 shader_stack[14],
945                 shader_stack[15],
946                 0);
948 printf("HistogramMain::handle_opengl %d %d %d %d shader=%d\n", 
949 aggregate_interpolation, 
950 aggregate_gamma,
951 aggregate_colorbalance,
952 current_shader,
953 shader);
955         float input_min_r[2] = { 0, 0 };
956         float input_min_g[2] = { 0, 0 };
957         float input_min_b[2] = { 0, 0 };
958         float input_min_v[2] = { 0, 0 };
959         float input_max_r[2] = { 1, 1 };
960         float input_max_g[2] = { 1, 1 };
961         float input_max_b[2] = { 1, 1 };
962         float input_max_v[2] = { 1, 1 };
963         float output_min[4] = { 0, 0, 0, 0 };
964         float output_scale[4] = { 1, 1, 1, 1 };
966 // Red
967         HistogramPoint *point1, *point2;
968         
969 #define CONVERT_POINT(index, input_min, input_max) \
970         point1 = config.points[index].first; \
971         point2 = config.points[index].last; \
972         if(point1) \
973         { \
974                 input_min[0] = point1->x; \
975                 input_min[1] = point1->y; \
976                 if(point2 != point1) \
977                 { \
978                         input_max[0] = point2->x; \
979                         input_max[1] = point2->y; \
980                 } \
981         }
983         CONVERT_POINT(HISTOGRAM_RED, input_min_r, input_max_r);
984         CONVERT_POINT(HISTOGRAM_GREEN, input_min_g, input_max_g);
985         CONVERT_POINT(HISTOGRAM_BLUE, input_min_b, input_max_b);
986         CONVERT_POINT(HISTOGRAM_VALUE, input_min_v, input_max_v);
988 // printf("min x    min y    max x    max y\n");
989 // printf("%f %f %f %f\n", input_min_r[0], input_min_r[1], input_max_r[0], input_max_r[1]);
990 // printf("%f %f %f %f\n", input_min_g[0], input_min_g[1], input_max_g[0], input_max_g[1]);
991 // printf("%f %f %f %f\n", input_min_b[0], input_min_b[1], input_max_b[0], input_max_b[1]);
992 // printf("%f %f %f %f\n", input_min_v[0], input_min_v[1], input_max_v[0], input_max_v[1]);
994         for(int i = 0; i < HISTOGRAM_MODES; i++)
995         {
996                 output_min[i] = config.output_min[i];
997                 output_scale[i] = config.output_max[i] - config.output_min[i];
998         }
1000         if(shader > 0)
1001         {
1002                 glUseProgram(shader);
1003                 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
1004                 if(aggregate_gamma) GAMMA_UNIFORMS(shader)
1005                 if(aggregate_interpolation) INTERPOLATE_UNIFORMS(shader)
1006                 if(aggregate_colorbalance) COLORBALANCE_UNIFORMS(shader)
1007                 glUniform2fv(glGetUniformLocation(shader, "input_min_r"), 1, input_min_r);
1008                 glUniform2fv(glGetUniformLocation(shader, "input_min_g"), 1, input_min_g);
1009                 glUniform2fv(glGetUniformLocation(shader, "input_min_b"), 1, input_min_b);
1010                 glUniform2fv(glGetUniformLocation(shader, "input_min_v"), 1, input_min_v);
1011                 glUniform2fv(glGetUniformLocation(shader, "input_max_r"), 1, input_max_r);
1012                 glUniform2fv(glGetUniformLocation(shader, "input_max_g"), 1, input_max_g);
1013                 glUniform2fv(glGetUniformLocation(shader, "input_max_b"), 1, input_max_b);
1014                 glUniform2fv(glGetUniformLocation(shader, "input_max_v"), 1, input_max_v);
1015                 glUniform4fv(glGetUniformLocation(shader, "output_min"), 1, output_min);
1016                 glUniform4fv(glGetUniformLocation(shader, "output_scale"), 1, output_scale);
1017         }
1019         get_output()->init_screen();
1020         get_output()->bind_texture(0);
1022         glDisable(GL_BLEND);
1024 // Draw the affected half
1025         if(config.split)
1026         {
1027                 glBegin(GL_TRIANGLES);
1028                 glNormal3f(0, 0, 1.0);
1030                 glTexCoord2f(0.0 / get_output()->get_texture_w(), 
1031                         0.0 / get_output()->get_texture_h());
1032                 glVertex3f(0.0, -(float)get_output()->get_h(), 0);
1035                 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(), 
1036                         (float)get_output()->get_h() / get_output()->get_texture_h());
1037                 glVertex3f((float)get_output()->get_w(), -0.0, 0);
1039                 glTexCoord2f(0.0 / get_output()->get_texture_w(), 
1040                         (float)get_output()->get_h() / get_output()->get_texture_h());
1041                 glVertex3f(0.0, -0.0, 0);
1044                 glEnd();
1045         }
1046         else
1047         {
1048                 get_output()->draw_texture();
1049         }
1051         glUseProgram(0);
1053 // Draw the unaffected half
1054         if(config.split)
1055         {
1056                 glBegin(GL_TRIANGLES);
1057                 glNormal3f(0, 0, 1.0);
1060                 glTexCoord2f(0.0 / get_output()->get_texture_w(), 
1061                         0.0 / get_output()->get_texture_h());
1062                 glVertex3f(0.0, -(float)get_output()->get_h(), 0);
1064                 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(), 
1065                         0.0 / get_output()->get_texture_h());
1066                 glVertex3f((float)get_output()->get_w(), 
1067                         -(float)get_output()->get_h(), 0);
1069                 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(), 
1070                         (float)get_output()->get_h() / get_output()->get_texture_h());
1071                 glVertex3f((float)get_output()->get_w(), -0.0, 0);
1074                 glEnd();
1075         }
1077         get_output()->set_opengl_state(VFrame::SCREEN);
1078 #endif
1092 HistogramPackage::HistogramPackage()
1093  : LoadPackage()
1100 HistogramUnit::HistogramUnit(HistogramEngine *server, 
1101         HistogramMain *plugin)
1102  : LoadClient(server)
1104         this->plugin = plugin;
1105         this->server = server;
1106         for(int i = 0; i < HISTOGRAM_MODES; i++)
1107                 accum[i] = new int[HISTOGRAM_SLOTS];
1110 HistogramUnit::~HistogramUnit()
1112         for(int i = 0; i < HISTOGRAM_MODES; i++)
1113                 delete [] accum[i];
1116 void HistogramUnit::process_package(LoadPackage *package)
1118         HistogramPackage *pkg = (HistogramPackage*)package;
1120         if(server->operation == HistogramEngine::HISTOGRAM)
1121         {
1122                 int do_value = server->do_value;
1125 #define HISTOGRAM_HEAD(type) \
1126 { \
1127         for(int i = pkg->start; i < pkg->end; i++) \
1128         { \
1129                 type *row = (type*)data->get_rows()[i]; \
1130                 for(int j = 0; j < w; j++) \
1131                 {
1133 #define HISTOGRAM_TAIL(components) \
1134 /* Value takes the maximum of the output RGB values */ \
1135                         if(do_value) \
1136                         { \
1137                                 CLAMP(r, 0, HISTOGRAM_SLOTS - 1); \
1138                                 CLAMP(g, 0, HISTOGRAM_SLOTS - 1); \
1139                                 CLAMP(b, 0, HISTOGRAM_SLOTS - 1); \
1140                                 r_out = lookup_r[r]; \
1141                                 g_out = lookup_g[g]; \
1142                                 b_out = lookup_b[b]; \
1143 /*                              v = (r * 76 + g * 150 + b * 29) >> 8; */ \
1144                                 v = MAX(r_out, g_out); \
1145                                 v = MAX(v, b_out); \
1146                                 v += -HISTOGRAM_MIN * 0xffff / 100; \
1147                                 CLAMP(v, 0, HISTOGRAM_SLOTS - 1); \
1148                                 accum_v[v]++; \
1149                         } \
1151                         r += -HISTOGRAM_MIN * 0xffff / 100; \
1152                         g += -HISTOGRAM_MIN * 0xffff / 100; \
1153                         b += -HISTOGRAM_MIN * 0xffff / 100; \
1154                         CLAMP(r, 0, HISTOGRAM_SLOTS - 1); \
1155                         CLAMP(g, 0, HISTOGRAM_SLOTS - 1); \
1156                         CLAMP(b, 0, HISTOGRAM_SLOTS - 1); \
1157                         accum_r[r]++; \
1158                         accum_g[g]++; \
1159                         accum_b[b]++; \
1160                         row += components; \
1161                 } \
1162         } \
1168                 VFrame *data = server->data;
1169                 int w = data->get_w();
1170                 int h = data->get_h();
1171                 int *accum_r = accum[HISTOGRAM_RED];
1172                 int *accum_g = accum[HISTOGRAM_GREEN];
1173                 int *accum_b = accum[HISTOGRAM_BLUE];
1174                 int *accum_v = accum[HISTOGRAM_VALUE];
1175                 int32_t r, g, b, a, y, u, v;
1176                 int r_out, g_out, b_out;
1177                 int *lookup_r = plugin->preview_lookup[HISTOGRAM_RED];
1178                 int *lookup_g = plugin->preview_lookup[HISTOGRAM_GREEN];
1179                 int *lookup_b = plugin->preview_lookup[HISTOGRAM_BLUE];
1181                 switch(data->get_color_model())
1182                 {
1183                         case BC_RGB888:
1184                                 HISTOGRAM_HEAD(unsigned char)
1185                                 r = (row[0] << 8) | row[0];
1186                                 g = (row[1] << 8) | row[1];
1187                                 b = (row[2] << 8) | row[2];
1188                                 HISTOGRAM_TAIL(3)
1189                                 break;
1190                         case BC_RGB_FLOAT:
1191                                 HISTOGRAM_HEAD(float)
1192                                 r = (int)(row[0] * 0xffff);
1193                                 g = (int)(row[1] * 0xffff);
1194                                 b = (int)(row[2] * 0xffff);
1195                                 HISTOGRAM_TAIL(3)
1196                                 break;
1197                         case BC_YUV888:
1198                                 HISTOGRAM_HEAD(unsigned char)
1199                                 y = (row[0] << 8) | row[0];
1200                                 u = (row[1] << 8) | row[1];
1201                                 v = (row[2] << 8) | row[2];
1202                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1203                                 HISTOGRAM_TAIL(3)
1204                                 break;
1205                         case BC_RGBA8888:
1206                                 HISTOGRAM_HEAD(unsigned char)
1207                                 r = (row[0] << 8) | row[0];
1208                                 g = (row[1] << 8) | row[1];
1209                                 b = (row[2] << 8) | row[2];
1210                                 HISTOGRAM_TAIL(4)
1211                                 break;
1212                         case BC_RGBA_FLOAT:
1213                                 HISTOGRAM_HEAD(float)
1214                                 r = (int)(row[0] * 0xffff);
1215                                 g = (int)(row[1] * 0xffff);
1216                                 b = (int)(row[2] * 0xffff);
1217                                 HISTOGRAM_TAIL(4)
1218                                 break;
1219                         case BC_YUVA8888:
1220                                 HISTOGRAM_HEAD(unsigned char)
1221                                 y = (row[0] << 8) | row[0];
1222                                 u = (row[1] << 8) | row[1];
1223                                 v = (row[2] << 8) | row[2];
1224                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1225                                 HISTOGRAM_TAIL(4)
1226                                 break;
1227                         case BC_RGB161616:
1228                                 HISTOGRAM_HEAD(uint16_t)
1229                                 r = row[0];
1230                                 g = row[1];
1231                                 b = row[2];
1232                                 HISTOGRAM_TAIL(3)
1233                                 break;
1234                         case BC_YUV161616:
1235                                 HISTOGRAM_HEAD(uint16_t)
1236                                 y = row[0];
1237                                 u = row[1];
1238                                 v = row[2];
1239                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1240                                 HISTOGRAM_TAIL(3)
1241                                 break;
1242                         case BC_RGBA16161616:
1243                                 HISTOGRAM_HEAD(uint16_t)
1244                                 r = row[0];
1245                                 g = row[1];
1246                                 b = row[2];
1247                                 HISTOGRAM_TAIL(3)
1248                                 break;
1249                         case BC_YUVA16161616:
1250                                 HISTOGRAM_HEAD(uint16_t)
1251                                 y = row[0];
1252                                 u = row[1];
1253                                 v = row[2];
1254                                 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1255                                 HISTOGRAM_TAIL(4)
1256                                 break;
1257                 }
1258         }
1259         else
1260         if(server->operation == HistogramEngine::APPLY)
1261         {
1265 #define PROCESS(type, components) \
1266 { \
1267         for(int i = pkg->start; i < pkg->end; i++) \
1268         { \
1269                 type *row = (type*)input->get_rows()[i]; \
1270                 for(int j = 0; j < w; j++) \
1271                 { \
1272                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
1273                         continue; \
1274                         row[0] = lookup_r[row[0]]; \
1275                         row[1] = lookup_g[row[1]]; \
1276                         row[2] = lookup_b[row[2]]; \
1277                         row += components; \
1278                 } \
1279         } \
1282 #define PROCESS_YUV(type, components, max) \
1283 { \
1284         for(int i = pkg->start; i < pkg->end; i++) \
1285         { \
1286                 type *row = (type*)input->get_rows()[i]; \
1287                 for(int j = 0; j < w; j++) \
1288                 { \
1289                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
1290                         continue; \
1291 /* Convert to 16 bit RGB */ \
1292                         if(max == 0xff) \
1293                         { \
1294                                 y = (row[0] << 8) | row[0]; \
1295                                 u = (row[1] << 8) | row[1]; \
1296                                 v = (row[2] << 8) | row[2]; \
1297                         } \
1298                         else \
1299                         { \
1300                                 y = row[0]; \
1301                                 u = row[1]; \
1302                                 v = row[2]; \
1303                         } \
1305                         plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
1307 /* Look up in RGB domain */ \
1308                         r = lookup_r[r]; \
1309                         g = lookup_g[g]; \
1310                         b = lookup_b[b]; \
1312 /* Convert to 16 bit YUV */ \
1313                         plugin->yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
1315                         if(max == 0xff) \
1316                         { \
1317                                 row[0] = y >> 8; \
1318                                 row[1] = u >> 8; \
1319                                 row[2] = v >> 8; \
1320                         } \
1321                         else \
1322                         { \
1323                                 row[0] = y; \
1324                                 row[1] = u; \
1325                                 row[2] = v; \
1326                         } \
1327                         row += components; \
1328                 } \
1329         } \
1332 #define PROCESS_FLOAT(components) \
1333 { \
1334         for(int i = pkg->start; i < pkg->end; i++) \
1335         { \
1336                 float *row = (float*)input->get_rows()[i]; \
1337                 for(int j = 0; j < w; j++) \
1338                 { \
1339                         if ( plugin->config.split && ((j + i * w / h) < w) ) \
1340                         continue; \
1341                         float r = row[0]; \
1342                         float g = row[1]; \
1343                         float b = row[2]; \
1345                         r = plugin->calculate_smooth(r, HISTOGRAM_RED); \
1346                         g = plugin->calculate_smooth(g, HISTOGRAM_GREEN); \
1347                         b = plugin->calculate_smooth(b, HISTOGRAM_BLUE); \
1349                         row[0] = r; \
1350                         row[1] = g; \
1351                         row[2] = b; \
1353                         row += components; \
1354                 } \
1355         } \
1359                 VFrame *input = plugin->input;
1360                 VFrame *output = plugin->output;
1361                 int w = input->get_w();
1362                 int h = input->get_h();
1363                 int *lookup_r = plugin->lookup[0];
1364                 int *lookup_g = plugin->lookup[1];
1365                 int *lookup_b = plugin->lookup[2];
1366                 int r, g, b, y, u, v, a;
1367                 switch(input->get_color_model())
1368                 {
1369                         case BC_RGB888:
1370                                 PROCESS(unsigned char, 3)
1371                                 break;
1372                         case BC_RGB_FLOAT:
1373                                 PROCESS_FLOAT(3);
1374                                 break;
1375                         case BC_RGBA8888:
1376                                 PROCESS(unsigned char, 4)
1377                                 break;
1378                         case BC_RGBA_FLOAT:
1379                                 PROCESS_FLOAT(4);
1380                                 break;
1381                         case BC_RGB161616:
1382                                 PROCESS(uint16_t, 3)
1383                                 break;
1384                         case BC_RGBA16161616:
1385                                 PROCESS(uint16_t, 4)
1386                                 break;
1387                         case BC_YUV888:
1388                                 PROCESS_YUV(unsigned char, 3, 0xff)
1389                                 break;
1390                         case BC_YUVA8888:
1391                                 PROCESS_YUV(unsigned char, 4, 0xff)
1392                                 break;
1393                         case BC_YUV161616:
1394                                 PROCESS_YUV(uint16_t, 3, 0xffff)
1395                                 break;
1396                         case BC_YUVA16161616:
1397                                 PROCESS_YUV(uint16_t, 4, 0xffff)
1398                                 break;
1399                 }
1400         }
1408 HistogramEngine::HistogramEngine(HistogramMain *plugin, 
1409         int total_clients, 
1410         int total_packages)
1411  : LoadServer(total_clients, total_packages)
1413         this->plugin = plugin;
1416 void HistogramEngine::init_packages()
1418         switch(operation)
1419         {
1420                 case HISTOGRAM:
1421                         total_size = data->get_h();
1422                         break;
1423                 case APPLY:
1424                         total_size = data->get_h();
1425                         break;
1426         }
1429         int package_size = (int)((float)total_size / 
1430                         get_total_packages() + 1);
1431         int start = 0;
1433         for(int i = 0; i < get_total_packages(); i++)
1434         {
1435                 HistogramPackage *package = (HistogramPackage*)get_package(i);
1436                 package->start = total_size * i / get_total_packages();
1437                 package->end = total_size * (i + 1) / get_total_packages();
1438         }
1440 // Initialize clients here in case some don't get run.
1441         for(int i = 0; i < get_total_clients(); i++)
1442         {
1443                 HistogramUnit *unit = (HistogramUnit*)get_client(i);
1444                 for(int i = 0; i < HISTOGRAM_MODES; i++)
1445                         bzero(unit->accum[i], sizeof(int) * HISTOGRAM_SLOTS);
1446         }
1450 LoadClient* HistogramEngine::new_client()
1452         return new HistogramUnit(this, plugin);
1455 LoadPackage* HistogramEngine::new_package()
1457         return new HistogramPackage;
1460 void HistogramEngine::process_packages(int operation, VFrame *data, int do_value)
1462         this->data = data;
1463         this->operation = operation;
1464         this->do_value = do_value;
1465         LoadServer::process_packages();