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"
29 #include "bcprogressbox.h"
30 #include "bcsignals.h"
34 #include "histogram.h"
35 #include "histogramconfig.h"
36 #include "histogramwindow.h"
39 #include "loadbalance.h"
40 #include "localsession.h"
41 #include "mainsession.h"
43 #include "playback3d.h"
44 #include "pluginserver.h"
47 #include "workarounds.h"
49 #include "aggregated.h"
50 #include "../colorbalance/aggregated.h"
51 #include "../interpolate/aggregated.h"
52 #include "../gamma/aggregated.h"
55 class HistogramEngine;
56 class HistogramWindow;
59 REGISTER_PLUGIN(HistogramMain)
61 HistogramMain::HistogramMain(PluginServer *server)
62 : PluginVClient(server)
65 for( int i=0; i<HISTOGRAM_MODES; ++i ) {
66 lookup[i] = new int[0x10000];
67 preview_lookup[i] = new int[0x10000];
68 accum[i] = new int64_t[HISTOGRAM_SLOTS];
69 bzero(accum[i], sizeof(int64_t)*HISTOGRAM_SLOTS);
72 mode = HISTOGRAM_VALUE;
85 HistogramMain::~HistogramMain()
88 for( int i=0; i<HISTOGRAM_MODES; ++i ) {
90 delete [] preview_lookup[i];
96 const char* HistogramMain::plugin_title() { return N_("Histogram"); }
97 int HistogramMain::is_realtime() { return 1; }
101 NEW_WINDOW_MACRO(HistogramMain, HistogramWindow)
103 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
105 void HistogramMain::render_gui(void *data)
107 if( !thread ) return;
108 HistogramWindow *window = (HistogramWindow*)thread->window;
109 HistogramMain *plugin = (HistogramMain*)data;
110 //update gui client instance, needed for drawing
111 for( int i=0; i<HISTOGRAM_MODES; ++i ) {
112 config.low_input[i] = plugin->config.low_input[i];
113 config.high_input[i] = plugin->config.high_input[i];
114 memcpy(accum[i], plugin->accum[i], HISTOGRAM_SLOTS*sizeof(*accum));
116 window->lock_window("HistogramMain::render_gui 2");
117 // draw all if reconfigure
118 int reconfig = plugin->need_reconfigure;
119 // Always draw the histogram but don't update widgets if automatic
120 int auto_rgb = reconfig ? 1 : config.automatic && mode != HISTOGRAM_VALUE ? 1 : 0;
121 window->update(1, auto_rgb, auto_rgb, reconfig);
122 window->unlock_window();
125 void HistogramMain::update_gui()
128 ((HistogramWindow*)thread->window)->lock_window("HistogramMain::update_gui");
129 int reconfigure = load_configuration();
131 ((HistogramWindow*)thread->window)->update(1, 1, 1, 1);
132 ((HistogramWindow*)thread->window)->unlock_window();
137 void HistogramMain::save_data(KeyFrame *keyframe)
140 // cause data to be stored directly in text
141 output.set_shared_output(keyframe->xbuf);
142 output.tag.set_title("HISTOGRAM");
144 char string[BCTEXTLEN];
146 output.tag.set_property("AUTOMATIC", config.automatic);
147 output.tag.set_property("THRESHOLD", config.threshold);
148 output.tag.set_property("PLOT", config.plot);
149 output.tag.set_property("SUM_FRAMES", config.sum_frames);
150 output.tag.set_property("SPLIT", config.split);
151 output.tag.set_property("LOG_SLIDER", config.log_slider);
152 output.tag.set_property("W", w);
153 output.tag.set_property("H", h);
154 output.tag.set_property("PARADE", parade);
155 output.tag.set_property("MODE", mode);
157 for( int i=0; i<HISTOGRAM_MODES; ++i ) {
158 sprintf(string, "LOW_OUTPUT_%d", i);
159 output.tag.set_property(string, config.low_output[i]);
160 sprintf(string, "HIGH_OUTPUT_%d", i);
161 output.tag.set_property(string, config.high_output[i]);
162 sprintf(string, "LOW_INPUT_%d", i);
163 output.tag.set_property(string, config.low_input[i]);
164 sprintf(string, "HIGH_INPUT_%d", i);
165 output.tag.set_property(string, config.high_input[i]);
166 sprintf(string, "GAMMA_%d", i);
167 output.tag.set_property(string, config.gamma[i]);
171 output.tag.set_title("/HISTOGRAM");
173 output.append_newline();
174 output.terminate_string();
177 void HistogramMain::read_data(KeyFrame *keyframe)
181 input.set_shared_input(keyframe->xbuf);
184 while( !(result = input.read_tag()) ) {
185 if( input.tag.title_is("HISTOGRAM") ) {
186 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
187 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
188 config.plot = input.tag.get_property("PLOT", config.plot);
189 config.sum_frames = input.tag.get_property("SUM_FRAMES", config.sum_frames);
190 config.split = input.tag.get_property("SPLIT", config.split);
191 config.log_slider = input.tag.get_property("LOG_SLIDER", config.log_slider);
193 if( is_defaults() ) {
194 w = input.tag.get_property("W", w);
195 h = input.tag.get_property("H", h);
196 parade = input.tag.get_property("PARADE", parade);
197 mode = input.tag.get_property("MODE", mode);
200 char string[BCTEXTLEN];
201 for( int i=0; i<HISTOGRAM_MODES; ++i ) {
202 sprintf(string, "LOW_OUTPUT_%d", i);
203 config.low_output[i] = input.tag.get_property(string, config.low_output[i]);
204 sprintf(string, "HIGH_OUTPUT_%d", i);
205 config.high_output[i] = input.tag.get_property(string, config.high_output[i]);
206 sprintf(string, "GAMMA_%d", i);
207 config.gamma[i] = input.tag.get_property(string, config.gamma[i]);
209 if( i == HISTOGRAM_VALUE || !config.automatic ) {
210 sprintf(string, "LOW_INPUT_%d", i);
211 config.low_input[i] = input.tag.get_property(string, config.low_input[i]);
212 sprintf(string, "HIGH_INPUT_%d", i);
213 config.high_input[i] = input.tag.get_property(string, config.high_input[i]);
222 float HistogramMain::calculate_level(float input, int mode, int use_value)
226 // Scale to input range
227 if( !EQUIV(config.high_input[mode], config.low_input[mode]) ) {
228 output = input < config.low_input[mode] ? 0 :
229 (input - config.low_input[mode]) /
230 (config.high_input[mode] - config.low_input[mode]);
235 if( !EQUIV(config.gamma[mode], 0) ) {
236 output = pow(output, 1.0 / config.gamma[mode]);
237 CLAMP(output, 0, 100.0);
241 if( use_value && mode != HISTOGRAM_VALUE )
242 output = calculate_level(output, HISTOGRAM_VALUE, 0);
244 // scale to output range
245 if( !EQUIV(config.low_output[mode], config.high_output[mode]) ) {
246 output = output * (config.high_output[mode] - config.low_output[mode]) +
247 config.low_output[mode];
250 CLAMP(output, 0, 1.0);
254 void HistogramMain::calculate_histogram(VFrame *data, int do_value)
257 int cpus = data->get_w() * data->get_h() / 0x80000 + 2;
258 int smps = get_project_smp();
259 if( cpus > smps ) cpus = smps;
260 engine = new HistogramEngine(this, cpus, cpus);
263 engine->process_packages(HistogramEngine::HISTOGRAM, data, do_value);
266 HistogramUnit *unit = (HistogramUnit*)engine->get_client(0);
269 for( int i=0; i<HISTOGRAM_MODES; ++i )
270 memcpy(accum[i], unit->accum[i], sizeof(int64_t)*HISTOGRAM_SLOTS);
274 for( int i=k,n=engine->get_total_clients(); i<n; ++i ) {
275 unit = (HistogramUnit*)engine->get_client(i);
276 for( int j=0; j<HISTOGRAM_MODES; ++j ) {
277 int64_t *in = unit->accum[j], *out = accum[j];
278 for( int k=HISTOGRAM_SLOTS; --k>=0; ) *out++ += *in++;
282 // Remove top and bottom from calculations. Doesn't work in high
283 // precision colormodels.
284 for( int i=0; i<HISTOGRAM_MODES; ++i ) {
286 accum[i][HISTOGRAM_SLOTS - 1] = 0;
292 void HistogramMain::calculate_automatic(VFrame *data)
294 calculate_histogram(data, 0);
295 config.reset_points(1);
298 for( int i=0; i<3; ++i ) {
299 int64_t *accum = this->accum[i];
300 int64_t sz = data->get_w() * data->get_h();
301 int64_t pixels = sz * frames;
302 float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
303 int threshold = (int)(white_fraction * pixels);
304 float min_level = 0.0, max_level = 1.0;
306 // Get histogram slot above threshold of pixels
308 for( int j=0; j<HISTOGRAM_SLOTS; ++j ) {
310 if( total >= threshold ) {
311 max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
316 // Get histogram slot below threshold of pixels
318 for( int j=HISTOGRAM_SLOTS; --j> 0; ) {
320 if( total >= threshold ) {
321 min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
326 config.low_input[i] = min_level;
327 config.high_input[i] = max_level;
332 int HistogramMain::calculate_use_opengl()
334 // glHistogram doesn't work.
335 int result = get_use_opengl() &&
337 (!config.plot || !gui_open());
342 int HistogramMain::process_buffer(VFrame *frame,
343 int64_t start_position,
346 need_reconfigure = load_configuration();
347 int use_opengl = calculate_use_opengl();
348 sum_frames = last_position == start_position ? config.sum_frames : 0;
349 last_position = get_direction() == PLAY_FORWARD ?
350 start_position+1 : start_position-1;
352 this->output = frame;
353 int cpus = input->get_w() * input->get_h() / 0x80000 + 2;
354 int smps = get_project_smp();
355 if( cpus > smps ) cpus = smps;
357 engine = new HistogramEngine(this, cpus, cpus);
358 read_frame(frame, 0, start_position, frame_rate, use_opengl);
359 if( config.automatic )
360 calculate_automatic(frame);
362 // Generate curves for value histogram
363 tabulate_curve(lookup, 0);
364 tabulate_curve(preview_lookup, 0, 0x10000);
365 // Need to get the luminance values.
366 calculate_histogram(input, 1);
367 send_render_gui(this);
370 if( need_reconfigure || config.automatic || config.plot ) {
371 // Calculate new curves
372 // Generate transfer tables with value function for integer colormodels.
373 tabulate_curve(lookup, 1);
376 // Apply histogram in hardware
381 engine->process_packages(HistogramEngine::APPLY, input, 0);
385 void HistogramMain::tabulate_curve(int **table, int idx, int use_value, int len)
388 int *curve = table[idx];
389 for( int i=0; i<len; ++i ) {
390 curve[i] = calculate_level((float)i/len1, idx, use_value) * len1;
391 CLAMP(curve[i], 0, len1);
395 void HistogramMain::tabulate_curve(int **table, int use_value, int len)
397 // uint8 rgb is 8 bit, all others are converted to 16 bit RGB
399 int color_model = input->get_color_model();
400 len = color_model == BC_RGB888 || color_model == BC_RGBA8888 ?
403 for( int i=0; i<3; ++i )
404 tabulate_curve(table, i, use_value, len);
407 int HistogramMain::handle_opengl()
410 // Functions to get pixel from either previous effect or texture
411 static const char *histogram_get_pixel1 =
412 "vec4 histogram_get_pixel()\n"
414 " return gl_FragColor;\n"
417 static const char *histogram_get_pixel2 =
418 "uniform sampler2D tex;\n"
419 "vec4 histogram_get_pixel()\n"
421 " return texture2D(tex, gl_TexCoord[0].st);\n"
424 static const char *head_frag =
425 "uniform vec4 low_input;\n"
426 "uniform vec4 high_input;\n"
427 "uniform vec4 gamma;\n"
428 "uniform vec4 low_output;\n"
429 "uniform vec4 output_scale;\n"
432 " float temp = 0.0;\n";
434 static const char *get_rgb_frag =
435 " vec4 pixel = histogram_get_pixel();\n";
437 static const char *get_yuv_frag =
438 " vec4 pixel = histogram_get_pixel();\n"
439 YUV_TO_RGB_FRAG("pixel");
441 #define APPLY_INPUT_CURVE(PIXEL, LOW_INPUT, HIGH_INPUT, GAMMA) \
442 "// apply input curve\n" \
443 " temp = (" PIXEL " - " LOW_INPUT ") / \n" \
444 " (" HIGH_INPUT " - " LOW_INPUT ");\n" \
445 " temp = max(temp, 0.0);\n" \
446 " " PIXEL " = pow(temp, 1.0 / " GAMMA ");\n"
450 static const char *apply_histogram_frag =
451 APPLY_INPUT_CURVE("pixel.r", "low_input.r", "high_input.r", "gamma.r")
452 APPLY_INPUT_CURVE("pixel.g", "low_input.g", "high_input.g", "gamma.g")
453 APPLY_INPUT_CURVE("pixel.b", "low_input.b", "high_input.b", "gamma.b")
454 "// apply output curve\n"
455 " pixel.rgb *= output_scale.rgb;\n"
456 " pixel.rgb += low_output.rgb;\n"
457 APPLY_INPUT_CURVE("pixel.r", "low_input.a", "high_input.a", "gamma.a")
458 APPLY_INPUT_CURVE("pixel.g", "low_input.a", "high_input.a", "gamma.a")
459 APPLY_INPUT_CURVE("pixel.b", "low_input.a", "high_input.a", "gamma.a")
460 "// apply output curve\n"
461 " pixel.rgb *= vec3(output_scale.a, output_scale.a, output_scale.a);\n"
462 " pixel.rgb += vec3(low_output.a, low_output.a, low_output.a);\n";
464 static const char *put_rgb_frag =
465 " gl_FragColor = pixel;\n"
468 static const char *put_yuv_frag =
469 RGB_TO_YUV_FRAG("pixel")
470 " gl_FragColor = pixel;\n"
475 get_output()->to_texture();
476 get_output()->enable_opengl();
478 const char *shader_stack[16];
479 memset(shader_stack,0, sizeof(shader_stack));
480 int current_shader = 0;
482 int need_color_matrix = BC_CModels::is_yuv(get_output()->get_color_model()) ? 1 : 0;
483 if( need_color_matrix )
484 shader_stack[current_shader++] = bc_gl_colors;
486 int aggregate_interpolation = 0;
487 int aggregate_gamma = 0;
488 int aggregate_colorbalance = 0;
489 // All aggregation possibilities must be accounted for because unsupported
490 // effects can get in between the aggregation members.
491 if(!strcmp(get_output()->get_prev_effect(2), _("Interpolate Pixels")) &&
492 !strcmp(get_output()->get_prev_effect(1), _("Gamma")) &&
493 !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
495 aggregate_interpolation = 1;
497 aggregate_colorbalance = 1;
500 if(!strcmp(get_output()->get_prev_effect(1), _("Gamma")) &&
501 !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
504 aggregate_colorbalance = 1;
507 if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
508 !strcmp(get_output()->get_prev_effect(0), _("Gamma")))
510 aggregate_interpolation = 1;
514 if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
515 !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
517 aggregate_interpolation = 1;
518 aggregate_colorbalance = 1;
521 if(!strcmp(get_output()->get_prev_effect(0), _("Interpolate Pixels")))
522 aggregate_interpolation = 1;
524 if(!strcmp(get_output()->get_prev_effect(0), _("Gamma")))
527 if(!strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
528 aggregate_colorbalance = 1;
530 // The order of processing is fixed by this sequence
531 if(aggregate_interpolation)
532 INTERPOLATE_COMPILE(shader_stack, current_shader);
535 GAMMA_COMPILE(shader_stack, current_shader,
536 aggregate_interpolation);
538 if(aggregate_colorbalance)
539 COLORBALANCE_COMPILE(shader_stack, current_shader,
540 aggregate_interpolation || aggregate_gamma);
542 shader_stack[current_shader++] =
543 aggregate_interpolation || aggregate_gamma || aggregate_colorbalance ?
544 histogram_get_pixel1 : histogram_get_pixel2;
546 shader_stack[current_shader++] = head_frag;
547 shader_stack[current_shader++] = BC_CModels::is_yuv(get_output()->get_color_model()) ?
548 get_yuv_frag : get_rgb_frag;
549 shader_stack[current_shader++] = apply_histogram_frag;
550 shader_stack[current_shader++] = BC_CModels::is_yuv(get_output()->get_color_model()) ?
551 put_yuv_frag : put_rgb_frag;
553 shader_stack[current_shader] = 0;
554 unsigned int shader = VFrame::make_shader(shader_stack);
556 // printf("HistogramMain::handle_opengl %d %d %d %d shader=%d\n",
557 // aggregate_interpolation,
559 // aggregate_colorbalance,
567 float output_scale[4];
570 // printf("min x min y max x max y\n");
571 // printf("%f %f %f %f\n", input_min_r[0], input_min_r[1], input_max_r[0], input_max_r[1]);
572 // printf("%f %f %f %f\n", input_min_g[0], input_min_g[1], input_max_g[0], input_max_g[1]);
573 // printf("%f %f %f %f\n", input_min_b[0], input_min_b[1], input_max_b[0], input_max_b[1]);
574 // printf("%f %f %f %f\n", input_min_v[0], input_min_v[1], input_max_v[0], input_max_v[1]);
576 for(int i = 0; i < HISTOGRAM_MODES; i++)
578 low_input[i] = config.low_input[i];
579 high_input[i] = config.high_input[i];
580 gamma[i] = config.gamma[i];
581 low_output[i] = config.low_output[i];
582 output_scale[i] = config.high_output[i] - config.low_output[i];
587 glUseProgram(shader);
588 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
589 if(aggregate_gamma) GAMMA_UNIFORMS(shader);
590 if(aggregate_interpolation) INTERPOLATE_UNIFORMS(shader);
591 if(aggregate_colorbalance) COLORBALANCE_UNIFORMS(shader);
592 glUniform4fv(glGetUniformLocation(shader, "low_input"), 1, low_input);
593 glUniform4fv(glGetUniformLocation(shader, "high_input"), 1, high_input);
594 glUniform4fv(glGetUniformLocation(shader, "gamma"), 1, gamma);
595 glUniform4fv(glGetUniformLocation(shader, "low_output"), 1, low_output);
596 glUniform4fv(glGetUniformLocation(shader, "output_scale"), 1, output_scale);
597 if( need_color_matrix ) BC_GL_COLORS(shader);
600 get_output()->init_screen();
601 get_output()->bind_texture(0);
605 // Draw the affected half
608 glBegin(GL_TRIANGLES);
609 glNormal3f(0, 0, 1.0);
611 glTexCoord2f(0.0 / get_output()->get_texture_w(),
612 0.0 / get_output()->get_texture_h());
613 glVertex3f(0.0, -(float)get_output()->get_h(), 0);
616 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
617 (float)get_output()->get_h() / get_output()->get_texture_h());
618 glVertex3f((float)get_output()->get_w(), -0.0, 0);
620 glTexCoord2f(0.0 / get_output()->get_texture_w(),
621 (float)get_output()->get_h() / get_output()->get_texture_h());
622 glVertex3f(0.0, -0.0, 0);
629 get_output()->draw_texture();
634 // Draw the unaffected half
637 glBegin(GL_TRIANGLES);
638 glNormal3f(0, 0, 1.0);
641 glTexCoord2f(0.0 / get_output()->get_texture_w(),
642 0.0 / get_output()->get_texture_h());
643 glVertex3f(0.0, -(float)get_output()->get_h(), 0);
645 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
646 0.0 / get_output()->get_texture_h());
647 glVertex3f((float)get_output()->get_w(),
648 -(float)get_output()->get_h(), 0);
650 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
651 (float)get_output()->get_h() / get_output()->get_texture_h());
652 glVertex3f((float)get_output()->get_w(), -0.0, 0);
658 get_output()->set_opengl_state(VFrame::SCREEN);
664 HistogramPackage::HistogramPackage()
669 HistogramUnit::HistogramUnit(HistogramEngine *server,
670 HistogramMain *plugin)
673 this->plugin = plugin;
674 this->server = server;
675 for(int i = 0; i < HISTOGRAM_MODES; i++)
676 accum[i] = new int64_t[HISTOGRAM_SLOTS];
679 HistogramUnit::~HistogramUnit()
681 for(int i = 0; i < HISTOGRAM_MODES; i++)
685 void HistogramUnit::process_package(LoadPackage *package)
687 HistogramPackage *pkg = (HistogramPackage*)package;
688 switch( server->operation ) {
689 case HistogramEngine::HISTOGRAM: {
690 int do_value = server->do_value;
691 const int hmin = HISTOGRAM_MIN * 0xffff / 100;
692 const int slots1 = HISTOGRAM_SLOTS-1;
694 #define HISTOGRAM_HEAD(type) { \
695 type **rows = (type**)data->get_rows(); \
696 for( int iy=pkg->start; iy<pkg->end; ++iy ) { \
697 type *row = rows[iy]; \
698 for( int ix=0; ix<w; ++ix ) {
700 #define HISTOGRAM_TAIL(components) \
702 r_out = preview_r[bclip(r, 0, 0xffff)]; \
703 g_out = preview_g[bclip(g, 0, 0xffff)]; \
704 b_out = preview_b[bclip(b, 0, 0xffff)]; \
705 /* v = (r * 76 + g * 150 + b * 29) >> 8; */ \
706 /* Value takes the maximum of the output RGB values */ \
707 int v = MAX(r_out, g_out); v = MAX(v, b_out); \
708 ++accum_v[bclip(v -= hmin, 0, slots1)]; \
711 ++accum_r[bclip(r -= hmin, 0, slots1)]; \
712 ++accum_g[bclip(g -= hmin, 0, slots1)]; \
713 ++accum_b[bclip(b -= hmin, 0, slots1)]; \
719 VFrame *data = server->data;
720 int w = data->get_w();
721 //int h = data->get_h();
722 int64_t *accum_r = accum[HISTOGRAM_RED];
723 int64_t *accum_g = accum[HISTOGRAM_GREEN];
724 int64_t *accum_b = accum[HISTOGRAM_BLUE];
725 int64_t *accum_v = accum[HISTOGRAM_VALUE];
726 int32_t r, g, b, y, u, v;
727 int r_out, g_out, b_out;
728 int *preview_r = plugin->preview_lookup[HISTOGRAM_RED];
729 int *preview_g = plugin->preview_lookup[HISTOGRAM_GREEN];
730 int *preview_b = plugin->preview_lookup[HISTOGRAM_BLUE];
732 switch( data->get_color_model() ) {
734 HISTOGRAM_HEAD(unsigned char)
735 r = (row[0] << 8) | row[0];
736 g = (row[1] << 8) | row[1];
737 b = (row[2] << 8) | row[2];
741 HISTOGRAM_HEAD(float)
742 r = (int)(row[0] * 0xffff);
743 g = (int)(row[1] * 0xffff);
744 b = (int)(row[2] * 0xffff);
748 HISTOGRAM_HEAD(unsigned char)
749 y = (row[0] << 8) | row[0];
750 u = (row[1] << 8) | row[1];
751 v = (row[2] << 8) | row[2];
752 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
756 HISTOGRAM_HEAD(unsigned char)
757 r = (row[0] << 8) | row[0];
758 g = (row[1] << 8) | row[1];
759 b = (row[2] << 8) | row[2];
763 HISTOGRAM_HEAD(float)
764 r = (int)(row[0] * 0xffff);
765 g = (int)(row[1] * 0xffff);
766 b = (int)(row[2] * 0xffff);
770 HISTOGRAM_HEAD(unsigned char)
771 y = (row[0] << 8) | row[0];
772 u = (row[1] << 8) | row[1];
773 v = (row[2] << 8) | row[2];
774 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
778 HISTOGRAM_HEAD(uint16_t)
785 HISTOGRAM_HEAD(uint16_t)
789 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
792 case BC_RGBA16161616:
793 HISTOGRAM_HEAD(uint16_t)
799 case BC_YUVA16161616:
800 HISTOGRAM_HEAD(uint16_t)
804 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
809 case HistogramEngine::APPLY: {
811 #define PROCESS(type, components) { \
812 type **rows = (type**)input->get_rows(); \
813 for( int iy=pkg->start; iy<pkg->end; ++iy ) { \
814 type *row = rows[iy]; \
815 for( int ix=0; ix<w; ++ix ) { \
816 if( plugin->config.split && ((ix + (iy*w)/h) < w) ) \
818 row[0] = lookup_r[row[0]]; \
819 row[1] = lookup_g[row[1]]; \
820 row[2] = lookup_b[row[2]]; \
826 #define PROCESS_YUV(type, components, max) { \
827 type **rows = (type**)input->get_rows(); \
828 for( int iy=pkg->start; iy<pkg->end; ++iy ) { \
829 type *row = rows[iy]; \
830 for( int ix=0; ix<w; ++ix ) { \
831 if( plugin->config.split && ((ix + (iy*w)/h) < w) ) \
833 if( max == 0xff ) { /* Convert to 16 bit RGB */ \
834 y = (row[0] << 8) | row[0]; \
835 u = (row[1] << 8) | row[1]; \
836 v = (row[2] << 8) | row[2]; \
843 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
844 /* Look up in RGB domain */ \
848 /* Convert to 16 bit YUV */ \
849 YUV::yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
850 if( max == 0xff ) { \
865 #define PROCESS_FLOAT(components) { \
866 float **rows = (float**)input->get_rows(); \
867 for( int iy=pkg->start; iy<pkg->end; ++iy ) { \
868 float *row = rows[iy]; \
869 for( int ix=0; ix<w; ++ix ) { \
870 if( plugin->config.split && ((ix + (iy*w)/h) < w) ) \
875 row[0] = plugin->calculate_level(fr, HISTOGRAM_RED, 1); \
876 row[1] = plugin->calculate_level(fg, HISTOGRAM_GREEN, 1); \
877 row[2] = plugin->calculate_level(fb, HISTOGRAM_BLUE, 1); \
883 VFrame *input = plugin->input;
884 //VFrame *output = plugin->output;
885 int w = input->get_w();
886 int h = input->get_h();
887 int *lookup_r = plugin->lookup[0];
888 int *lookup_g = plugin->lookup[1];
889 int *lookup_b = plugin->lookup[2];
890 int r, g, b, y, u, v;
891 switch( input->get_color_model() ) {
893 PROCESS(unsigned char, 3)
899 PROCESS(unsigned char, 4)
907 case BC_RGBA16161616:
911 PROCESS_YUV(unsigned char, 3, 0xff)
914 PROCESS_YUV(unsigned char, 4, 0xff)
917 PROCESS_YUV(uint16_t, 3, 0xffff)
919 case BC_YUVA16161616:
920 PROCESS_YUV(uint16_t, 4, 0xffff)
928 HistogramEngine::HistogramEngine(HistogramMain *plugin,
929 int total_clients, int total_packages)
930 : LoadServer(total_clients, total_packages)
932 this->plugin = plugin;
935 void HistogramEngine::init_packages()
939 total_size = data->get_h();
942 total_size = data->get_h();
947 for( int i=0,n=get_total_packages(); i<n; ++i ) {
948 HistogramPackage *package = (HistogramPackage*)get_package(i);
949 package->start = start;
950 package->end = total_size * (i+1)/n;
951 start = package->end;
954 // Initialize clients here in case some don't get run.
955 for( int i=0,n=get_total_clients(); i<n; ++i ) {
956 HistogramUnit *unit = (HistogramUnit*)get_client(i);
957 for( int j=0; j<HISTOGRAM_MODES; ++j )
958 bzero(unit->accum[j], sizeof(int64_t) * HISTOGRAM_SLOTS);
962 LoadClient* HistogramEngine::new_client()
964 return new HistogramUnit(this, plugin);
967 LoadPackage* HistogramEngine::new_package()
969 return new HistogramPackage;
972 void HistogramEngine::process_packages(int operation, VFrame *data, int do_value)
975 this->operation = operation;
976 this->do_value = do_value;
977 LoadServer::process_packages();