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