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