4 * Copyright (C) 2008-2012 Adam Williams <broadcast at earthling dot net>
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.
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.
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
27 #include "bcdisplayinfo.h"
28 #include "bcsignals.h"
32 #include "histogram.h"
33 #include "histogramconfig.h"
34 #include "histogramwindow.h"
37 #include "loadbalance.h"
38 #include "playback3d.h"
41 #include "workarounds.h"
43 #include "aggregated.h"
44 #include "../colorbalance/aggregated.h"
45 #include "../interpolate/aggregated.h"
46 #include "../gamma/aggregated.h"
49 class HistogramEngine;
50 class HistogramWindow;
56 REGISTER_PLUGIN(HistogramMain)
66 HistogramMain::HistogramMain(PluginServer *server)
67 : PluginVClient(server)
71 for(int i = 0; i < HISTOGRAM_MODES; i++)
75 preview_lookup[i] = 0;
78 mode = HISTOGRAM_VALUE;
87 HistogramMain::~HistogramMain()
90 for(int i = 0; i < HISTOGRAM_MODES;i++)
94 delete [] preview_lookup[i];
99 const char* HistogramMain::plugin_title() { return N_("Histogram"); }
100 int HistogramMain::is_realtime() { return 1; }
104 NEW_WINDOW_MACRO(HistogramMain, HistogramWindow)
106 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
108 void HistogramMain::render_gui(void *data)
112 // Process just the RGB values to determine the automatic points or
113 // all the points if manual
114 if(!config.automatic)
116 // Generate curves for value histogram
117 // Lock out changes to curves
118 ((HistogramWindow*)thread->window)->lock_window("HistogramMain::render_gui 1");
119 tabulate_curve(HISTOGRAM_RED, 0);
120 tabulate_curve(HISTOGRAM_GREEN, 0);
121 tabulate_curve(HISTOGRAM_BLUE, 0);
122 ((HistogramWindow*)thread->window)->unlock_window();
125 calculate_histogram((VFrame*)data, !config.automatic);
130 calculate_automatic((VFrame*)data);
132 // Generate curves for value histogram
133 // Lock out changes to curves
134 ((HistogramWindow*)thread->window)->lock_window("HistogramMain::render_gui 1");
135 tabulate_curve(HISTOGRAM_RED, 0);
136 tabulate_curve(HISTOGRAM_GREEN, 0);
137 tabulate_curve(HISTOGRAM_BLUE, 0);
138 ((HistogramWindow*)thread->window)->unlock_window();
141 // Need a second pass to get the luminance values.
142 calculate_histogram((VFrame*)data, 1);
145 ((HistogramWindow*)thread->window)->lock_window("HistogramMain::render_gui 2");
146 // Always draw the histogram but don't update widgets if automatic
147 ((HistogramWindow*)thread->window)->update(1,
148 config.automatic && mode != HISTOGRAM_VALUE,
149 config.automatic && mode != HISTOGRAM_VALUE,
152 ((HistogramWindow*)thread->window)->unlock_window();
156 void HistogramMain::update_gui()
160 ((HistogramWindow*)thread->window)->lock_window("HistogramMain::update_gui");
161 int reconfigure = load_configuration();
164 ((HistogramWindow*)thread->window)->update(1,
169 ((HistogramWindow*)thread->window)->unlock_window();
176 void HistogramMain::save_data(KeyFrame *keyframe)
180 // cause data to be stored directly in text
181 output.set_shared_output(keyframe->xbuf);
182 output.tag.set_title("HISTOGRAM");
184 char string[BCTEXTLEN];
186 output.tag.set_property("AUTOMATIC", config.automatic);
187 output.tag.set_property("THRESHOLD", config.threshold);
188 output.tag.set_property("PLOT", config.plot);
189 output.tag.set_property("SPLIT", config.split);
190 output.tag.set_property("W", w);
191 output.tag.set_property("H", h);
192 output.tag.set_property("PARADE", parade);
193 output.tag.set_property("MODE", mode);
195 for(int i = 0; i < HISTOGRAM_MODES; i++)
197 sprintf(string, "LOW_OUTPUT_%d", i);
198 output.tag.set_property(string, config.low_output[i]);
199 sprintf(string, "HIGH_OUTPUT_%d", i);
200 output.tag.set_property(string, config.high_output[i]);
201 sprintf(string, "LOW_INPUT_%d", i);
202 output.tag.set_property(string, config.low_input[i]);
203 sprintf(string, "HIGH_INPUT_%d", i);
204 output.tag.set_property(string, config.high_input[i]);
205 sprintf(string, "GAMMA_%d", i);
206 output.tag.set_property(string, config.gamma[i]);
207 //printf("HistogramMain::save_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
211 output.tag.set_title("/HISTOGRAM");
213 output.append_newline();
214 output.terminate_string();
217 void HistogramMain::read_data(KeyFrame *keyframe)
221 input.set_shared_input(keyframe->xbuf);
228 result = input.read_tag();
232 if(input.tag.title_is("HISTOGRAM"))
234 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
235 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
236 config.plot = input.tag.get_property("PLOT", config.plot);
237 config.split = input.tag.get_property("SPLIT", config.split);
241 w = input.tag.get_property("W", w);
242 h = input.tag.get_property("H", h);
243 parade = input.tag.get_property("PARADE", parade);
244 mode = input.tag.get_property("MODE", mode);
247 char string[BCTEXTLEN];
248 for(int i = 0; i < HISTOGRAM_MODES; i++)
250 sprintf(string, "LOW_OUTPUT_%d", i);
251 config.low_output[i] = input.tag.get_property(string, config.low_output[i]);
252 sprintf(string, "HIGH_OUTPUT_%d", i);
253 config.high_output[i] = input.tag.get_property(string, config.high_output[i]);
254 sprintf(string, "GAMMA_%d", i);
255 config.gamma[i] = input.tag.get_property(string, config.gamma[i]);
257 if(i == HISTOGRAM_VALUE || !config.automatic)
259 sprintf(string, "LOW_INPUT_%d", i);
260 config.low_input[i] = input.tag.get_property(string, config.low_input[i]);
261 sprintf(string, "HIGH_INPUT_%d", i);
262 config.high_input[i] = input.tag.get_property(string, config.high_input[i]);
264 //printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
274 float HistogramMain::calculate_level(float input,
280 // Scale to input range
281 if(!EQUIV(config.high_input[mode], config.low_input[mode]))
283 output = input < config.low_input[mode] ? 0 :
284 (input - config.low_input[mode]) /
285 (config.high_input[mode] - config.low_input[mode]);
294 if(!EQUIV(config.gamma[mode], 0))
296 output = pow(output, 1.0 / config.gamma[mode]);
297 CLAMP(output, 0, 1.0);
301 if(use_value && mode != HISTOGRAM_VALUE)
303 output = calculate_level(output, HISTOGRAM_VALUE, 0);
309 // scale to output range
310 if(!EQUIV(config.low_output[mode], config.high_output[mode]))
312 output = output * (config.high_output[mode] - config.low_output[mode]) +
313 config.low_output[mode];
316 CLAMP(output, 0, 1.0);
323 void HistogramMain::calculate_histogram(VFrame *data, int do_value)
327 int cpus = data->get_w() * data->get_h() / 0x80000 + 2;
328 int smps = get_project_smp();
329 if( cpus > smps ) cpus = smps;
330 engine = new HistogramEngine(this, cpus, cpus);
334 for(int i = 0; i < HISTOGRAM_MODES; i++)
335 accum[i] = new int[HISTOGRAM_SLOTS];
338 engine->process_packages(HistogramEngine::HISTOGRAM, data, do_value);
340 for(int i = 0; i < engine->get_total_clients(); i++)
342 HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
346 for(int j = 0; j < HISTOGRAM_MODES; j++)
348 memcpy(accum[j], unit->accum[j], sizeof(int) * HISTOGRAM_SLOTS);
353 for(int j = 0; j < HISTOGRAM_MODES; j++)
356 int *in = unit->accum[j];
357 for(int k = 0; k < HISTOGRAM_SLOTS; k++)
363 // Remove top and bottom from calculations. Doesn't work in high
364 // precision colormodels.
365 for(int i = 0; i < HISTOGRAM_MODES; i++)
368 accum[i][HISTOGRAM_SLOTS - 1] = 0;
373 void HistogramMain::calculate_automatic(VFrame *data)
375 calculate_histogram(data, 0);
376 config.reset_points(1);
379 for(int i = 0; i < 3; i++)
381 int *accum = this->accum[i];
382 int pixels = data->get_w() * data->get_h();
383 float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
384 int threshold = (int)(white_fraction * pixels);
386 float max_level = 1.0;
387 float min_level = 0.0;
389 // Get histogram slot above threshold of pixels
390 for(int j = 0; j < HISTOGRAM_SLOTS; j++)
393 if(total >= threshold)
395 max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
400 // Get slot below 99% of pixels
402 for(int j = HISTOGRAM_SLOTS - 1; j >= 0; j--)
405 if(total >= threshold)
407 min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
413 config.low_input[i] = min_level;
414 config.high_input[i] = max_level;
422 int HistogramMain::calculate_use_opengl()
424 // glHistogram doesn't work.
425 int result = get_use_opengl() &&
427 (!config.plot || !gui_open());
432 int HistogramMain::process_buffer(VFrame *frame,
433 int64_t start_position,
436 int need_reconfigure = load_configuration();
440 int use_opengl = calculate_use_opengl();
442 //printf("%d\n", use_opengl);
449 // Apply histogram in hardware
450 if(use_opengl) return run_opengl();
453 this->output = frame;
456 int cpus = input->get_w() * input->get_h() / 0x80000 + 2;
457 int smps = get_project_smp();
458 if( cpus > smps ) cpus = smps;
459 engine = new HistogramEngine(this, cpus, cpus);
461 // Always plot to set the curves if automatic
462 if(config.plot || config.automatic) send_render_gui(frame);
464 // Generate tables here. The same table is used by many packages to render
465 // each horizontal stripe. Need to cover the entire output range in each
466 // table to avoid green borders
469 if(need_reconfigure ||
473 // Calculate new curves
476 calculate_automatic(input);
480 // Generate transfer tables with value function for integer colormodels.
481 for(int i = 0; i < 3; i++)
482 tabulate_curve(i, 1);
485 // printf("HistogramMain::process_buffer %d %f %f %f %f %f %f %f %f %f\n",
487 // config.low_input[HISTOGRAM_RED],
488 // config.gamma[HISTOGRAM_RED],
489 // config.high_input[HISTOGRAM_RED],
490 // config.low_input[HISTOGRAM_GREEN],
491 // config.gamma[HISTOGRAM_GREEN],
492 // config.high_input[HISTOGRAM_GREEN],
493 // config.low_input[HISTOGRAM_BLUE],
494 // config.gamma[HISTOGRAM_BLUE],
495 // config.high_input[HISTOGRAM_BLUE]);
500 engine->process_packages(HistogramEngine::APPLY, input, 0);
506 void HistogramMain::tabulate_curve(int subscript, int use_value)
509 if(!lookup[subscript])
510 lookup[subscript] = new int[HISTOGRAM_SLOTS];
511 if(!preview_lookup[subscript])
512 preview_lookup[subscript] = new int[HISTOGRAM_SLOTS];
514 //printf("HistogramMain::tabulate_curve %d input=%p\n", __LINE__, input);
517 // Generate lookup tables for integer colormodels
520 switch(input->get_color_model())
524 for(i = 0; i < 0x100; i++)
526 lookup[subscript][i] =
527 (int)(calculate_level((float)i / 0xff, subscript, use_value) *
529 CLAMP(lookup[subscript][i], 0, 0xff);
532 // All other integer colormodels are converted to 16 bit RGB
534 for(i = 0; i < 0x10000; i++)
536 lookup[subscript][i] =
537 (int)(calculate_level((float)i / 0xffff, subscript, use_value) *
539 CLAMP(lookup[subscript][i], 0, 0xffff);
541 // for(i = 0; i < 0x100; i++)
543 // if(subscript == HISTOGRAM_BLUE) printf("%d ", lookup[subscript][i * 0x100]);
545 // if(subscript == HISTOGRAM_BLUE) printf("\n");
551 // Lookup table for preview only used for GUI
554 for(i = 0; i < 0x10000; i++)
556 preview_lookup[subscript][i] =
557 (int)(calculate_level((float)i / 0xffff, subscript, use_value) *
559 CLAMP(preview_lookup[subscript][i], 0, 0xffff);
564 int HistogramMain::handle_opengl()
567 // Functions to get pixel from either previous effect or texture
568 static const char *histogram_get_pixel1 =
569 "vec4 histogram_get_pixel()\n"
571 " return gl_FragColor;\n"
574 static const char *histogram_get_pixel2 =
575 "uniform sampler2D tex;\n"
576 "vec4 histogram_get_pixel()\n"
578 " return texture2D(tex, gl_TexCoord[0].st);\n"
581 static const char *head_frag =
582 "uniform vec4 low_input;\n"
583 "uniform vec4 high_input;\n"
584 "uniform vec4 gamma;\n"
585 "uniform vec4 low_output;\n"
586 "uniform vec4 output_scale;\n"
589 " float temp = 0.0;\n";
591 static const char *get_rgb_frag =
592 " vec4 pixel = histogram_get_pixel();\n";
594 static const char *get_yuv_frag =
595 " vec4 pixel = histogram_get_pixel();\n"
596 YUV_TO_RGB_FRAG("pixel");
598 #define APPLY_INPUT_CURVE(PIXEL, LOW_INPUT, HIGH_INPUT, GAMMA) \
599 "// apply input curve\n" \
600 " temp = (" PIXEL " - " LOW_INPUT ") / \n" \
601 " (" HIGH_INPUT " - " LOW_INPUT ");\n" \
602 " temp = max(temp, 0.0);\n" \
603 " " PIXEL " = pow(temp, 1.0 / " GAMMA ");\n"
607 static const char *apply_histogram_frag =
608 APPLY_INPUT_CURVE("pixel.r", "low_input.r", "high_input.r", "gamma.r")
609 APPLY_INPUT_CURVE("pixel.g", "low_input.g", "high_input.g", "gamma.g")
610 APPLY_INPUT_CURVE("pixel.b", "low_input.b", "high_input.b", "gamma.b")
611 "// apply output curve\n"
612 " pixel.rgb *= output_scale.rgb;\n"
613 " pixel.rgb += low_output.rgb;\n"
614 APPLY_INPUT_CURVE("pixel.r", "low_input.a", "high_input.a", "gamma.a")
615 APPLY_INPUT_CURVE("pixel.g", "low_input.a", "high_input.a", "gamma.a")
616 APPLY_INPUT_CURVE("pixel.b", "low_input.a", "high_input.a", "gamma.a")
617 "// apply output curve\n"
618 " pixel.rgb *= vec3(output_scale.a, output_scale.a, output_scale.a);\n"
619 " pixel.rgb += vec3(low_output.a, low_output.a, low_output.a);\n";
621 static const char *put_rgb_frag =
622 " gl_FragColor = pixel;\n"
625 static const char *put_yuv_frag =
626 RGB_TO_YUV_FRAG("pixel")
627 " gl_FragColor = pixel;\n"
632 get_output()->to_texture();
633 get_output()->enable_opengl();
635 const char *shader_stack[16];
636 memset(shader_stack,0, sizeof(shader_stack));
637 int current_shader = 0;
639 int need_color_matrix = BC_CModels::is_yuv(get_output()->get_color_model()) ? 1 : 0;
640 if( need_color_matrix )
641 shader_stack[current_shader++] = bc_gl_colors;
643 int aggregate_interpolation = 0;
644 int aggregate_gamma = 0;
645 int aggregate_colorbalance = 0;
646 // All aggregation possibilities must be accounted for because unsupported
647 // effects can get in between the aggregation members.
648 if(!strcmp(get_output()->get_prev_effect(2), _("Interpolate Pixels")) &&
649 !strcmp(get_output()->get_prev_effect(1), _("Gamma")) &&
650 !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
652 aggregate_interpolation = 1;
654 aggregate_colorbalance = 1;
657 if(!strcmp(get_output()->get_prev_effect(1), _("Gamma")) &&
658 !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
661 aggregate_colorbalance = 1;
664 if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
665 !strcmp(get_output()->get_prev_effect(0), _("Gamma")))
667 aggregate_interpolation = 1;
671 if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
672 !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
674 aggregate_interpolation = 1;
675 aggregate_colorbalance = 1;
678 if(!strcmp(get_output()->get_prev_effect(0), _("Interpolate Pixels")))
679 aggregate_interpolation = 1;
681 if(!strcmp(get_output()->get_prev_effect(0), _("Gamma")))
684 if(!strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
685 aggregate_colorbalance = 1;
687 // The order of processing is fixed by this sequence
688 if(aggregate_interpolation)
689 INTERPOLATE_COMPILE(shader_stack, current_shader);
692 GAMMA_COMPILE(shader_stack, current_shader,
693 aggregate_interpolation);
695 if(aggregate_colorbalance)
696 COLORBALANCE_COMPILE(shader_stack, current_shader,
697 aggregate_interpolation || aggregate_gamma);
699 shader_stack[current_shader++] =
700 aggregate_interpolation || aggregate_gamma || aggregate_colorbalance ?
701 histogram_get_pixel1 : histogram_get_pixel2;
703 shader_stack[current_shader++] = head_frag;
704 shader_stack[current_shader++] = BC_CModels::is_yuv(get_output()->get_color_model()) ?
705 get_yuv_frag : get_rgb_frag;
706 shader_stack[current_shader++] = apply_histogram_frag;
707 shader_stack[current_shader++] = BC_CModels::is_yuv(get_output()->get_color_model()) ?
708 put_yuv_frag : put_rgb_frag;
710 shader_stack[current_shader] = 0;
711 unsigned int shader = VFrame::make_shader(shader_stack);
713 // printf("HistogramMain::handle_opengl %d %d %d %d shader=%d\n",
714 // aggregate_interpolation,
716 // aggregate_colorbalance,
724 float output_scale[4];
727 // printf("min x min y max x max y\n");
728 // printf("%f %f %f %f\n", input_min_r[0], input_min_r[1], input_max_r[0], input_max_r[1]);
729 // printf("%f %f %f %f\n", input_min_g[0], input_min_g[1], input_max_g[0], input_max_g[1]);
730 // printf("%f %f %f %f\n", input_min_b[0], input_min_b[1], input_max_b[0], input_max_b[1]);
731 // printf("%f %f %f %f\n", input_min_v[0], input_min_v[1], input_max_v[0], input_max_v[1]);
733 for(int i = 0; i < HISTOGRAM_MODES; i++)
735 low_input[i] = config.low_input[i];
736 high_input[i] = config.high_input[i];
737 gamma[i] = config.gamma[i];
738 low_output[i] = config.low_output[i];
739 output_scale[i] = config.high_output[i] - config.low_output[i];
744 glUseProgram(shader);
745 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
746 if(aggregate_gamma) GAMMA_UNIFORMS(shader);
747 if(aggregate_interpolation) INTERPOLATE_UNIFORMS(shader);
748 if(aggregate_colorbalance) COLORBALANCE_UNIFORMS(shader);
749 glUniform4fv(glGetUniformLocation(shader, "low_input"), 1, low_input);
750 glUniform4fv(glGetUniformLocation(shader, "high_input"), 1, high_input);
751 glUniform4fv(glGetUniformLocation(shader, "gamma"), 1, gamma);
752 glUniform4fv(glGetUniformLocation(shader, "low_output"), 1, low_output);
753 glUniform4fv(glGetUniformLocation(shader, "output_scale"), 1, output_scale);
754 if( need_color_matrix ) BC_GL_COLORS(shader);
757 get_output()->init_screen();
758 get_output()->bind_texture(0);
762 // Draw the affected half
765 glBegin(GL_TRIANGLES);
766 glNormal3f(0, 0, 1.0);
768 glTexCoord2f(0.0 / get_output()->get_texture_w(),
769 0.0 / get_output()->get_texture_h());
770 glVertex3f(0.0, -(float)get_output()->get_h(), 0);
773 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
774 (float)get_output()->get_h() / get_output()->get_texture_h());
775 glVertex3f((float)get_output()->get_w(), -0.0, 0);
777 glTexCoord2f(0.0 / get_output()->get_texture_w(),
778 (float)get_output()->get_h() / get_output()->get_texture_h());
779 glVertex3f(0.0, -0.0, 0);
786 get_output()->draw_texture();
791 // Draw the unaffected half
794 glBegin(GL_TRIANGLES);
795 glNormal3f(0, 0, 1.0);
798 glTexCoord2f(0.0 / get_output()->get_texture_w(),
799 0.0 / get_output()->get_texture_h());
800 glVertex3f(0.0, -(float)get_output()->get_h(), 0);
802 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
803 0.0 / get_output()->get_texture_h());
804 glVertex3f((float)get_output()->get_w(),
805 -(float)get_output()->get_h(), 0);
807 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
808 (float)get_output()->get_h() / get_output()->get_texture_h());
809 glVertex3f((float)get_output()->get_w(), -0.0, 0);
815 get_output()->set_opengl_state(VFrame::SCREEN);
831 HistogramPackage::HistogramPackage()
839 HistogramUnit::HistogramUnit(HistogramEngine *server,
840 HistogramMain *plugin)
843 this->plugin = plugin;
844 this->server = server;
845 for(int i = 0; i < HISTOGRAM_MODES; i++)
846 accum[i] = new int[HISTOGRAM_SLOTS];
849 HistogramUnit::~HistogramUnit()
851 for(int i = 0; i < HISTOGRAM_MODES; i++)
855 void HistogramUnit::process_package(LoadPackage *package)
857 HistogramPackage *pkg = (HistogramPackage*)package;
859 if(server->operation == HistogramEngine::HISTOGRAM)
861 int do_value = server->do_value;
864 #define HISTOGRAM_HEAD(type) \
866 for(int i = pkg->start; i < pkg->end; i++) \
868 type *row = (type*)data->get_rows()[i]; \
869 for(int j = 0; j < w; j++) \
872 #define HISTOGRAM_TAIL(components) \
873 /* Value takes the maximum of the output RGB values */ \
876 CLAMP(r, 0, HISTOGRAM_SLOTS - 1); \
877 CLAMP(g, 0, HISTOGRAM_SLOTS - 1); \
878 CLAMP(b, 0, HISTOGRAM_SLOTS - 1); \
879 r_out = lookup_r[r]; \
880 g_out = lookup_g[g]; \
881 b_out = lookup_b[b]; \
882 /* v = (r * 76 + g * 150 + b * 29) >> 8; */ \
883 v = MAX(r_out, g_out); \
885 v += -HISTOGRAM_MIN * 0xffff / 100; \
886 CLAMP(v, 0, HISTOGRAM_SLOTS - 1); \
890 r += -HISTOGRAM_MIN * 0xffff / 100; \
891 g += -HISTOGRAM_MIN * 0xffff / 100; \
892 b += -HISTOGRAM_MIN * 0xffff / 100; \
893 CLAMP(r, 0, HISTOGRAM_SLOTS - 1); \
894 CLAMP(g, 0, HISTOGRAM_SLOTS - 1); \
895 CLAMP(b, 0, HISTOGRAM_SLOTS - 1); \
907 VFrame *data = server->data;
908 int w = data->get_w();
909 //int h = data->get_h();
910 int *accum_r = accum[HISTOGRAM_RED];
911 int *accum_g = accum[HISTOGRAM_GREEN];
912 int *accum_b = accum[HISTOGRAM_BLUE];
913 int *accum_v = accum[HISTOGRAM_VALUE];
914 int32_t r, g, b, y, u, v;
915 int r_out, g_out, b_out;
916 int *lookup_r = plugin->preview_lookup[HISTOGRAM_RED];
917 int *lookup_g = plugin->preview_lookup[HISTOGRAM_GREEN];
918 int *lookup_b = plugin->preview_lookup[HISTOGRAM_BLUE];
920 switch(data->get_color_model())
923 HISTOGRAM_HEAD(unsigned char)
924 r = (row[0] << 8) | row[0];
925 g = (row[1] << 8) | row[1];
926 b = (row[2] << 8) | row[2];
930 HISTOGRAM_HEAD(float)
931 r = (int)(row[0] * 0xffff);
932 g = (int)(row[1] * 0xffff);
933 b = (int)(row[2] * 0xffff);
937 HISTOGRAM_HEAD(unsigned char)
938 y = (row[0] << 8) | row[0];
939 u = (row[1] << 8) | row[1];
940 v = (row[2] << 8) | row[2];
941 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
945 HISTOGRAM_HEAD(unsigned char)
946 r = (row[0] << 8) | row[0];
947 g = (row[1] << 8) | row[1];
948 b = (row[2] << 8) | row[2];
952 HISTOGRAM_HEAD(float)
953 r = (int)(row[0] * 0xffff);
954 g = (int)(row[1] * 0xffff);
955 b = (int)(row[2] * 0xffff);
959 HISTOGRAM_HEAD(unsigned char)
960 y = (row[0] << 8) | row[0];
961 u = (row[1] << 8) | row[1];
962 v = (row[2] << 8) | row[2];
963 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
967 HISTOGRAM_HEAD(uint16_t)
974 HISTOGRAM_HEAD(uint16_t)
978 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
981 case BC_RGBA16161616:
982 HISTOGRAM_HEAD(uint16_t)
988 case BC_YUVA16161616:
989 HISTOGRAM_HEAD(uint16_t)
993 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
999 if(server->operation == HistogramEngine::APPLY)
1004 #define PROCESS(type, components) \
1006 for(int i = pkg->start; i < pkg->end; i++) \
1008 type *row = (type*)input->get_rows()[i]; \
1009 for(int j = 0; j < w; j++) \
1011 if ( plugin->config.split && ((j + i * w / h) < w) ) \
1013 row[0] = lookup_r[row[0]]; \
1014 row[1] = lookup_g[row[1]]; \
1015 row[2] = lookup_b[row[2]]; \
1016 row += components; \
1021 #define PROCESS_YUV(type, components, max) \
1023 for(int i = pkg->start; i < pkg->end; i++) \
1025 type *row = (type*)input->get_rows()[i]; \
1026 for(int j = 0; j < w; j++) \
1028 if ( plugin->config.split && ((j + i * w / h) < w) ) \
1030 /* Convert to 16 bit RGB */ \
1033 y = (row[0] << 8) | row[0]; \
1034 u = (row[1] << 8) | row[1]; \
1035 v = (row[2] << 8) | row[2]; \
1044 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
1046 /* Look up in RGB domain */ \
1051 /* Convert to 16 bit YUV */ \
1052 YUV::yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
1066 row += components; \
1071 #define PROCESS_FLOAT(components) \
1073 for(int i = pkg->start; i < pkg->end; i++) \
1075 float *row = (float*)input->get_rows()[i]; \
1076 for(int j = 0; j < w; j++) \
1078 if ( plugin->config.split && ((j + i * w / h) < w) ) \
1084 r = plugin->calculate_level(r, HISTOGRAM_RED, 1); \
1085 g = plugin->calculate_level(g, HISTOGRAM_GREEN, 1); \
1086 b = plugin->calculate_level(b, HISTOGRAM_BLUE, 1); \
1092 row += components; \
1098 VFrame *input = plugin->input;
1099 //VFrame *output = plugin->output;
1100 int w = input->get_w();
1101 int h = input->get_h();
1102 int *lookup_r = plugin->lookup[0];
1103 int *lookup_g = plugin->lookup[1];
1104 int *lookup_b = plugin->lookup[2];
1105 int r, g, b, y, u, v;
1106 switch(input->get_color_model())
1109 PROCESS(unsigned char, 3)
1115 PROCESS(unsigned char, 4)
1121 PROCESS(uint16_t, 3)
1123 case BC_RGBA16161616:
1124 PROCESS(uint16_t, 4)
1127 PROCESS_YUV(unsigned char, 3, 0xff)
1130 PROCESS_YUV(unsigned char, 4, 0xff)
1133 PROCESS_YUV(uint16_t, 3, 0xffff)
1135 case BC_YUVA16161616:
1136 PROCESS_YUV(uint16_t, 4, 0xffff)
1147 HistogramEngine::HistogramEngine(HistogramMain *plugin,
1150 : LoadServer(total_clients, total_packages)
1152 this->plugin = plugin;
1155 void HistogramEngine::init_packages()
1160 total_size = data->get_h();
1163 total_size = data->get_h();
1168 //int package_size = (int)((float)total_size / get_total_packages() + 1);
1171 for(int i = 0; i < get_total_packages(); i++)
1173 HistogramPackage *package = (HistogramPackage*)get_package(i);
1174 package->start = total_size * i / get_total_packages();
1175 package->end = total_size * (i + 1) / get_total_packages();
1178 // Initialize clients here in case some don't get run.
1179 for(int i = 0; i < get_total_clients(); i++)
1181 HistogramUnit *unit = (HistogramUnit*)get_client(i);
1182 for(int i = 0; i < HISTOGRAM_MODES; i++)
1183 bzero(unit->accum[i], sizeof(int) * HISTOGRAM_SLOTS);
1188 LoadClient* HistogramEngine::new_client()
1190 return new HistogramUnit(this, plugin);
1193 LoadPackage* HistogramEngine::new_package()
1195 return new HistogramPackage;
1198 void HistogramEngine::process_packages(int operation, VFrame *data, int do_value)
1201 this->operation = operation;
1202 this->do_value = do_value;
1203 LoadServer::process_packages();