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)
66 for( int i=0; i<HISTOGRAM_MODES; ++i ) {
69 preview_lookup[i] = 0;
72 mode = HISTOGRAM_VALUE;
84 HistogramMain::~HistogramMain()
87 for( int i=0; i<HISTOGRAM_MODES; ++i ) {
90 delete [] preview_lookup[i];
97 const char* HistogramMain::plugin_title() { return N_("Histogram"); }
98 int HistogramMain::is_realtime() { return 1; }
102 NEW_WINDOW_MACRO(HistogramMain, HistogramWindow)
104 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
106 void HistogramMain::render_gui(void *data)
108 input = (VFrame*)data;
110 // Process just the RGB values to determine the automatic points or
111 // all the points if manual
112 if( !config.automatic ) {
113 // Generate curves for value histogram
114 // Lock out changes to curves
115 ((HistogramWindow*)thread->window)->lock_window("HistogramMain::render_gui 1");
116 tabulate_curve(HISTOGRAM_RED, 0);
117 tabulate_curve(HISTOGRAM_GREEN, 0);
118 tabulate_curve(HISTOGRAM_BLUE, 0);
119 tabulate_curve(preview_lookup, HISTOGRAM_RED, 0x10000, 0);
120 tabulate_curve(preview_lookup, HISTOGRAM_GREEN, 0x10000, 0);
121 tabulate_curve(preview_lookup, HISTOGRAM_BLUE, 0x10000, 0);
122 ((HistogramWindow*)thread->window)->unlock_window();
125 calculate_histogram(input, !config.automatic);
127 if( config.automatic ) {
128 calculate_automatic(input);
129 // Generate curves for value histogram
130 // Lock out changes to curves
131 ((HistogramWindow*)thread->window)->lock_window("HistogramMain::render_gui 1");
132 tabulate_curve(HISTOGRAM_RED, 0);
133 tabulate_curve(HISTOGRAM_GREEN, 0);
134 tabulate_curve(HISTOGRAM_BLUE, 0);
135 tabulate_curve(preview_lookup, HISTOGRAM_RED, 0x10000, 0);
136 tabulate_curve(preview_lookup, HISTOGRAM_GREEN, 0x10000, 0);
137 tabulate_curve(preview_lookup, HISTOGRAM_BLUE, 0x10000, 0);
138 ((HistogramWindow*)thread->window)->unlock_window();
139 // Need a second pass to get the luminance values.
140 calculate_histogram(input, 1);
143 ((HistogramWindow*)thread->window)->lock_window("HistogramMain::render_gui 2");
144 // Always draw the histogram but don't update widgets if automatic
145 ((HistogramWindow*)thread->window)->update(1,
146 config.automatic && mode != HISTOGRAM_VALUE,
147 config.automatic && mode != HISTOGRAM_VALUE,
150 ((HistogramWindow*)thread->window)->unlock_window();
154 void HistogramMain::update_gui()
157 ((HistogramWindow*)thread->window)->lock_window("HistogramMain::update_gui");
158 int reconfigure = load_configuration();
160 ((HistogramWindow*)thread->window)->update(1, 1, 1, 1);
161 ((HistogramWindow*)thread->window)->unlock_window();
166 void HistogramMain::save_data(KeyFrame *keyframe)
170 // cause data to be stored directly in text
171 output.set_shared_output(keyframe->xbuf);
172 output.tag.set_title("HISTOGRAM");
174 char string[BCTEXTLEN];
176 output.tag.set_property("AUTOMATIC", config.automatic);
177 output.tag.set_property("THRESHOLD", config.threshold);
178 output.tag.set_property("PLOT", config.plot);
179 output.tag.set_property("SPLIT", config.split);
180 output.tag.set_property("FRAMES", config.frames);
181 output.tag.set_property("LOG_SLIDER", config.log_slider);
182 output.tag.set_property("W", w);
183 output.tag.set_property("H", h);
184 output.tag.set_property("PARADE", parade);
185 output.tag.set_property("MODE", mode);
187 for( int i=0; i<HISTOGRAM_MODES; ++i ) {
188 sprintf(string, "LOW_OUTPUT_%d", i);
189 output.tag.set_property(string, config.low_output[i]);
190 sprintf(string, "HIGH_OUTPUT_%d", i);
191 output.tag.set_property(string, config.high_output[i]);
192 sprintf(string, "LOW_INPUT_%d", i);
193 output.tag.set_property(string, config.low_input[i]);
194 sprintf(string, "HIGH_INPUT_%d", i);
195 output.tag.set_property(string, config.high_input[i]);
196 sprintf(string, "GAMMA_%d", i);
197 output.tag.set_property(string, config.gamma[i]);
201 output.tag.set_title("/HISTOGRAM");
203 output.append_newline();
204 output.terminate_string();
207 void HistogramMain::read_data(KeyFrame *keyframe)
211 input.set_shared_input(keyframe->xbuf);
214 while( !(result = input.read_tag()) ) {
215 if( input.tag.title_is("HISTOGRAM") ) {
216 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
217 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
218 config.plot = input.tag.get_property("PLOT", config.plot);
219 config.split = input.tag.get_property("SPLIT", config.split);
220 config.frames = input.tag.get_property("FRAMES", config.frames);
221 config.log_slider = input.tag.get_property("LOG_SLIDER", config.log_slider);
223 if( is_defaults() ) {
224 w = input.tag.get_property("W", w);
225 h = input.tag.get_property("H", h);
226 parade = input.tag.get_property("PARADE", parade);
227 mode = input.tag.get_property("MODE", mode);
230 char string[BCTEXTLEN];
231 for( int i=0; i<HISTOGRAM_MODES; ++i ) {
232 sprintf(string, "LOW_OUTPUT_%d", i);
233 config.low_output[i] = input.tag.get_property(string, config.low_output[i]);
234 sprintf(string, "HIGH_OUTPUT_%d", i);
235 config.high_output[i] = input.tag.get_property(string, config.high_output[i]);
236 sprintf(string, "GAMMA_%d", i);
237 config.gamma[i] = input.tag.get_property(string, config.gamma[i]);
239 if( i == HISTOGRAM_VALUE || !config.automatic ) {
240 sprintf(string, "LOW_INPUT_%d", i);
241 config.low_input[i] = input.tag.get_property(string, config.low_input[i]);
242 sprintf(string, "HIGH_INPUT_%d", i);
243 config.high_input[i] = input.tag.get_property(string, config.high_input[i]);
252 float HistogramMain::calculate_level(float input, int mode, int use_value)
256 // Scale to input range
257 if( !EQUIV(config.high_input[mode], config.low_input[mode]) ) {
258 output = input < config.low_input[mode] ? 0 :
259 (input - config.low_input[mode]) /
260 (config.high_input[mode] - config.low_input[mode]);
265 if( !EQUIV(config.gamma[mode], 0) ) {
266 output = pow(output, 1.0 / config.gamma[mode]);
267 CLAMP(output, 0, 1.0);
271 if( use_value && mode != HISTOGRAM_VALUE )
272 output = calculate_level(output, HISTOGRAM_VALUE, 0);
274 // scale to output range
275 if( !EQUIV(config.low_output[mode], config.high_output[mode]) ) {
276 output = output * (config.high_output[mode] - config.low_output[mode]) +
277 config.low_output[mode];
280 CLAMP(output, 0, 1.0);
284 void HistogramMain::calculate_histogram(VFrame *data, int do_value)
287 int cpus = data->get_w() * data->get_h() / 0x80000 + 2;
288 int smps = get_project_smp();
289 if( cpus > smps ) cpus = smps;
290 engine = new HistogramEngine(this, cpus, cpus);
293 for( int i=0; i<HISTOGRAM_MODES; ++i )
294 accum[i] = new int[HISTOGRAM_SLOTS];
297 engine->process_packages(HistogramEngine::HISTOGRAM, data, do_value);
299 HistogramUnit *unit = (HistogramUnit*)engine->get_client(0);
300 for( int i=0; i<HISTOGRAM_MODES; ++i )
301 memcpy(accum[i], unit->accum[i], sizeof(int)*HISTOGRAM_SLOTS);
303 for( int i=1,n=engine->get_total_clients(); i<n; ++i ) {
304 unit = (HistogramUnit*)engine->get_client(i);
305 for( int j=0; j<HISTOGRAM_MODES; ++j ) {
306 int *in = unit->accum[j], *out = accum[j];
307 for( int k=HISTOGRAM_SLOTS; --k>=0; ) *out++ += *in++;
311 // Remove top and bottom from calculations. Doesn't work in high
312 // precision colormodels.
313 for( int i=0; i<HISTOGRAM_MODES; ++i ) {
315 accum[i][HISTOGRAM_SLOTS - 1] = 0;
320 void HistogramMain::calculate_automatic(VFrame *data)
322 calculate_histogram(data, 0);
323 config.reset_points(1);
326 for( int i=0; i<3; ++i ) {
327 int *accum = this->accum[i];
328 int pixels = data->get_w() * data->get_h();
329 float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
330 int threshold = (int)(white_fraction * pixels);
331 float min_level = 0.0, max_level = 1.0;
333 // Get histogram slot above threshold of pixels
334 for( int j=0, total=0; j<HISTOGRAM_SLOTS; ++j ) {
336 if( total >= threshold ) {
337 max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
342 // Get slot below 99% of pixels
343 for( int j=HISTOGRAM_SLOTS, total=0; --j> 0; ) {
345 if( total >= threshold ) {
346 min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
351 config.low_input[i] = min_level;
352 config.high_input[i] = max_level;
357 int HistogramMain::calculate_use_opengl()
359 // glHistogram doesn't work.
360 int result = get_use_opengl() &&
362 (!config.plot || !gui_open());
367 int HistogramMain::process_buffer(VFrame *frame,
368 int64_t start_position,
371 int need_reconfigure = load_configuration();
372 int use_opengl = calculate_use_opengl();
375 this->output = frame;
376 int cpus = input->get_w() * input->get_h() / 0x80000 + 2;
377 int smps = get_project_smp();
378 if( cpus > smps ) cpus = smps;
380 engine = new HistogramEngine(this, cpus, cpus);
382 int frames = config.frames;
383 MWindow *mwindow = server->mwindow;
384 if( frames > 1 && (!mwindow || // dont scan during SELECT_REGION
385 mwindow->session->current_operation != SELECT_REGION ||
386 mwindow->edl->local_session->get_selectionstart() ==
387 mwindow->edl->local_session->get_selectionend() ) ) {
389 stripe_engine = new HistStripeEngine(this, cpus, cpus);
390 int fw = frame->get_w(), fh =frame->get_h();
391 new_temp(fw, fh, BC_RGB_FLOAT);
392 MWindow *mwindow = server->mwindow;
393 if( (mwindow && mwindow->session->current_operation == SELECT_REGION) ||
394 ( last_frames == frames && last_position-1 == start_position &&
395 fframe && fframe->get_w() == fw && fframe->get_h() == fh ) ) {
396 read_frame(temp, 0, start_position, frame_rate, use_opengl);
397 stripe_engine->process_packages(ADD_FFRM);
398 frame->transfer_from(temp);
400 else if( last_frames != frames || last_position != start_position ||
401 !fframe || fframe->get_w() != fw || fframe->get_h() != fh ) {
402 last_frames = frames;
403 last_position = start_position;
404 VFrame::get_temp(fframe, fw, fh, BC_RGB_FLOAT);
405 read_frame(fframe, 0, start_position+1, frame_rate, use_opengl);
406 BC_ProgressBox *progress = 0;
407 const char *progress_title = _("Histogram: scanning\n");
409 for( int i=2; i<frames; ++i ) {
410 read_frame(temp, 0, start_position+i, frame_rate, use_opengl);
411 stripe_engine->process_packages(ADD_TEMP);
412 if( !progress && gui_open() && frames > 2*frame_rate ) {
413 progress = new BC_ProgressBox(-1, -1, progress_title, frames);
416 if( progress && timer.get_difference() > 100 ) {
418 progress->update(i, 1);
419 char string[BCTEXTLEN];
420 sprintf(string, "%sframe: %d", progress_title, i);
421 progress->update_title(string, 1);
422 if( progress->is_cancelled() ) break;
424 if( progress && !gui_open() ) {
425 progress->stop_progress();
426 delete progress; progress = 0;
429 read_frame(temp, 0, start_position, frame_rate, use_opengl);
430 stripe_engine->process_packages(ADD_FFRMS);
431 frame->transfer_from(temp);
433 progress->stop_progress();
439 read_frame(temp, 0, start_position+frames-1, frame_rate, use_opengl);
440 stripe_engine->process_packages(ADD_TEMPS);
441 frame->transfer_from(fframe);
442 read_frame(temp, 0, start_position, frame_rate, use_opengl);
443 stripe_engine->process_packages(SUB_TEMPS);
448 read_frame(frame, 0, start_position, frame_rate, use_opengl);
450 // if to plot histogram
451 if(config.plot) send_render_gui(frame);
453 // Generate tables here. The same table is used by many packages to render
454 // each horizontal stripe. Need to cover the entire output range in each
455 // table to avoid green borders
458 if( need_reconfigure || !lookup[0] || config.automatic ) {
459 // Calculate new curves
460 if( config.automatic )
461 calculate_automatic(input);
462 // Generate transfer tables with value function for integer colormodels.
463 for( int i=0; i<3; ++i )
464 tabulate_curve(i, 1);
467 // Apply histogram in hardware
472 engine->process_packages(HistogramEngine::APPLY, input, 0);
476 void HistogramMain::tabulate_curve(int **table, int idx, int len, int use_value)
478 if( !table[idx] ) // must use max demand here
479 table[idx] = new int[0x10000];
480 int *curve = table[idx], len1 = len-1;
481 for( int i=0; i<len; ++i ) {
482 curve[i] = calculate_level((float)i/len1, idx, use_value) * len1;
483 CLAMP(curve[i], 0, len1);
487 void HistogramMain::tabulate_curve(int idx, int use_value)
489 // uint8 rgb is 8 bit, all others are converted to 16 bit RGB
490 int color_model = input->get_color_model();
491 int lookup_len = color_model == BC_RGB888 ||
492 color_model == BC_RGBA8888 ? 0x100 : 0x10000;
493 tabulate_curve(lookup, idx, lookup_len, use_value);
496 int HistogramMain::handle_opengl()
499 // Functions to get pixel from either previous effect or texture
500 static const char *histogram_get_pixel1 =
501 "vec4 histogram_get_pixel()\n"
503 " return gl_FragColor;\n"
506 static const char *histogram_get_pixel2 =
507 "uniform sampler2D tex;\n"
508 "vec4 histogram_get_pixel()\n"
510 " return texture2D(tex, gl_TexCoord[0].st);\n"
513 static const char *head_frag =
514 "uniform vec4 low_input;\n"
515 "uniform vec4 high_input;\n"
516 "uniform vec4 gamma;\n"
517 "uniform vec4 low_output;\n"
518 "uniform vec4 output_scale;\n"
521 " float temp = 0.0;\n";
523 static const char *get_rgb_frag =
524 " vec4 pixel = histogram_get_pixel();\n";
526 static const char *get_yuv_frag =
527 " vec4 pixel = histogram_get_pixel();\n"
528 YUV_TO_RGB_FRAG("pixel");
530 #define APPLY_INPUT_CURVE(PIXEL, LOW_INPUT, HIGH_INPUT, GAMMA) \
531 "// apply input curve\n" \
532 " temp = (" PIXEL " - " LOW_INPUT ") / \n" \
533 " (" HIGH_INPUT " - " LOW_INPUT ");\n" \
534 " temp = max(temp, 0.0);\n" \
535 " " PIXEL " = pow(temp, 1.0 / " GAMMA ");\n"
539 static const char *apply_histogram_frag =
540 APPLY_INPUT_CURVE("pixel.r", "low_input.r", "high_input.r", "gamma.r")
541 APPLY_INPUT_CURVE("pixel.g", "low_input.g", "high_input.g", "gamma.g")
542 APPLY_INPUT_CURVE("pixel.b", "low_input.b", "high_input.b", "gamma.b")
543 "// apply output curve\n"
544 " pixel.rgb *= output_scale.rgb;\n"
545 " pixel.rgb += low_output.rgb;\n"
546 APPLY_INPUT_CURVE("pixel.r", "low_input.a", "high_input.a", "gamma.a")
547 APPLY_INPUT_CURVE("pixel.g", "low_input.a", "high_input.a", "gamma.a")
548 APPLY_INPUT_CURVE("pixel.b", "low_input.a", "high_input.a", "gamma.a")
549 "// apply output curve\n"
550 " pixel.rgb *= vec3(output_scale.a, output_scale.a, output_scale.a);\n"
551 " pixel.rgb += vec3(low_output.a, low_output.a, low_output.a);\n";
553 static const char *put_rgb_frag =
554 " gl_FragColor = pixel;\n"
557 static const char *put_yuv_frag =
558 RGB_TO_YUV_FRAG("pixel")
559 " gl_FragColor = pixel;\n"
564 get_output()->to_texture();
565 get_output()->enable_opengl();
567 const char *shader_stack[16];
568 memset(shader_stack,0, sizeof(shader_stack));
569 int current_shader = 0;
571 int need_color_matrix = BC_CModels::is_yuv(get_output()->get_color_model()) ? 1 : 0;
572 if( need_color_matrix )
573 shader_stack[current_shader++] = bc_gl_colors;
575 int aggregate_interpolation = 0;
576 int aggregate_gamma = 0;
577 int aggregate_colorbalance = 0;
578 // All aggregation possibilities must be accounted for because unsupported
579 // effects can get in between the aggregation members.
580 if(!strcmp(get_output()->get_prev_effect(2), _("Interpolate Pixels")) &&
581 !strcmp(get_output()->get_prev_effect(1), _("Gamma")) &&
582 !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
584 aggregate_interpolation = 1;
586 aggregate_colorbalance = 1;
589 if(!strcmp(get_output()->get_prev_effect(1), _("Gamma")) &&
590 !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
593 aggregate_colorbalance = 1;
596 if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
597 !strcmp(get_output()->get_prev_effect(0), _("Gamma")))
599 aggregate_interpolation = 1;
603 if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
604 !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
606 aggregate_interpolation = 1;
607 aggregate_colorbalance = 1;
610 if(!strcmp(get_output()->get_prev_effect(0), _("Interpolate Pixels")))
611 aggregate_interpolation = 1;
613 if(!strcmp(get_output()->get_prev_effect(0), _("Gamma")))
616 if(!strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
617 aggregate_colorbalance = 1;
619 // The order of processing is fixed by this sequence
620 if(aggregate_interpolation)
621 INTERPOLATE_COMPILE(shader_stack, current_shader);
624 GAMMA_COMPILE(shader_stack, current_shader,
625 aggregate_interpolation);
627 if(aggregate_colorbalance)
628 COLORBALANCE_COMPILE(shader_stack, current_shader,
629 aggregate_interpolation || aggregate_gamma);
631 shader_stack[current_shader++] =
632 aggregate_interpolation || aggregate_gamma || aggregate_colorbalance ?
633 histogram_get_pixel1 : histogram_get_pixel2;
635 shader_stack[current_shader++] = head_frag;
636 shader_stack[current_shader++] = BC_CModels::is_yuv(get_output()->get_color_model()) ?
637 get_yuv_frag : get_rgb_frag;
638 shader_stack[current_shader++] = apply_histogram_frag;
639 shader_stack[current_shader++] = BC_CModels::is_yuv(get_output()->get_color_model()) ?
640 put_yuv_frag : put_rgb_frag;
642 shader_stack[current_shader] = 0;
643 unsigned int shader = VFrame::make_shader(shader_stack);
645 // printf("HistogramMain::handle_opengl %d %d %d %d shader=%d\n",
646 // aggregate_interpolation,
648 // aggregate_colorbalance,
656 float output_scale[4];
659 // printf("min x min y max x max y\n");
660 // printf("%f %f %f %f\n", input_min_r[0], input_min_r[1], input_max_r[0], input_max_r[1]);
661 // printf("%f %f %f %f\n", input_min_g[0], input_min_g[1], input_max_g[0], input_max_g[1]);
662 // printf("%f %f %f %f\n", input_min_b[0], input_min_b[1], input_max_b[0], input_max_b[1]);
663 // printf("%f %f %f %f\n", input_min_v[0], input_min_v[1], input_max_v[0], input_max_v[1]);
665 for(int i = 0; i < HISTOGRAM_MODES; i++)
667 low_input[i] = config.low_input[i];
668 high_input[i] = config.high_input[i];
669 gamma[i] = config.gamma[i];
670 low_output[i] = config.low_output[i];
671 output_scale[i] = config.high_output[i] - config.low_output[i];
676 glUseProgram(shader);
677 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
678 if(aggregate_gamma) GAMMA_UNIFORMS(shader);
679 if(aggregate_interpolation) INTERPOLATE_UNIFORMS(shader);
680 if(aggregate_colorbalance) COLORBALANCE_UNIFORMS(shader);
681 glUniform4fv(glGetUniformLocation(shader, "low_input"), 1, low_input);
682 glUniform4fv(glGetUniformLocation(shader, "high_input"), 1, high_input);
683 glUniform4fv(glGetUniformLocation(shader, "gamma"), 1, gamma);
684 glUniform4fv(glGetUniformLocation(shader, "low_output"), 1, low_output);
685 glUniform4fv(glGetUniformLocation(shader, "output_scale"), 1, output_scale);
686 if( need_color_matrix ) BC_GL_COLORS(shader);
689 get_output()->init_screen();
690 get_output()->bind_texture(0);
694 // Draw the affected half
697 glBegin(GL_TRIANGLES);
698 glNormal3f(0, 0, 1.0);
700 glTexCoord2f(0.0 / get_output()->get_texture_w(),
701 0.0 / get_output()->get_texture_h());
702 glVertex3f(0.0, -(float)get_output()->get_h(), 0);
705 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
706 (float)get_output()->get_h() / get_output()->get_texture_h());
707 glVertex3f((float)get_output()->get_w(), -0.0, 0);
709 glTexCoord2f(0.0 / get_output()->get_texture_w(),
710 (float)get_output()->get_h() / get_output()->get_texture_h());
711 glVertex3f(0.0, -0.0, 0);
718 get_output()->draw_texture();
723 // Draw the unaffected half
726 glBegin(GL_TRIANGLES);
727 glNormal3f(0, 0, 1.0);
730 glTexCoord2f(0.0 / get_output()->get_texture_w(),
731 0.0 / get_output()->get_texture_h());
732 glVertex3f(0.0, -(float)get_output()->get_h(), 0);
734 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
735 0.0 / get_output()->get_texture_h());
736 glVertex3f((float)get_output()->get_w(),
737 -(float)get_output()->get_h(), 0);
739 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
740 (float)get_output()->get_h() / get_output()->get_texture_h());
741 glVertex3f((float)get_output()->get_w(), -0.0, 0);
747 get_output()->set_opengl_state(VFrame::SCREEN);
753 HistStripePackage::HistStripePackage()
758 HistStripeUnit::HistStripeUnit(HistStripeEngine *server, HistogramMain *plugin)
761 this->plugin = plugin;
762 this->server = server;
765 void HistStripeUnit::process_package(LoadPackage *package)
767 HistStripePackage *pkg = (HistStripePackage*)package;
768 int frames = plugin->config.frames;
769 float scale = 1. / frames;
770 int iy0 = pkg->y0, iy1 = pkg->y1;
771 int fw = plugin->fframe->get_w();
772 uint8_t **frows = plugin->fframe->get_rows();
773 uint8_t **trows = plugin->temp->get_rows();
774 switch( server->operation ) {
775 case ADD_TEMP: // add temp to fframe
776 for( int iy=iy0; iy<iy1; ++iy ) {
777 float *trow = (float *)trows[iy];
778 float *frow = (float *)frows[iy];
779 for( int ix=0; ix<fw; ++ix ) {
786 case ADD_FFRM: // add fframe to scaled temp
787 for( int iy=iy0; iy<iy1; ++iy ) {
788 float *trow = (float *)trows[iy];
789 float *frow = (float *)frows[iy];
790 for( int ix=0; ix<fw; ++ix ) {
791 *trow = *trow * scale + *frow++; ++trow;
792 *trow = *trow * scale + *frow++; ++trow;
793 *trow = *trow * scale + *frow++; ++trow;
797 case ADD_FFRMS: // add fframe to temp, scale temp, scale fframe
798 for( int iy=iy0; iy<iy1; ++iy ) {
799 float *trow = (float *)trows[iy];
800 float *frow = (float *)frows[iy];
801 for( int ix=0; ix<fw; ++ix ) {
802 *trow += *frow; *trow++ *= scale; *frow++ *= scale;
803 *trow += *frow; *trow++ *= scale; *frow++ *= scale;
804 *trow += *frow; *trow++ *= scale; *frow++ *= scale;
808 case ADD_TEMPS: // add scaled temp to fframe
809 for( int iy=iy0; iy<iy1; ++iy ) {
810 float *trow = (float *)trows[iy];
811 float *frow = (float *)frows[iy];
812 for( int ix=0; ix<fw; ++ix ) {
813 *frow++ += *trow++ * scale;
814 *frow++ += *trow++ * scale;
815 *frow++ += *trow++ * scale;
819 case SUB_TEMPS: // sub scaled temp from frame
820 for( int iy=iy0; iy<iy1; ++iy ) {
821 float *trow = (float *)trows[iy];
822 float *frow = (float *)frows[iy];
823 for( int ix=0; ix<fw; ++ix ) {
824 *frow++ -= *trow++ * scale;
825 *frow++ -= *trow++ * scale;
826 *frow++ -= *trow++ * scale;
833 HistStripeEngine::HistStripeEngine(HistogramMain *plugin,
834 int total_clients, int total_packages)
835 : LoadServer(total_clients, total_packages)
837 this->plugin = plugin;
839 void HistStripeEngine::init_packages()
841 int ih = plugin->input->get_h(), iy0 = 0;
842 for( int i=0,n=get_total_packages(); i<n; ) {
843 HistStripePackage *pkg = (HistStripePackage*)get_package(i);
844 int iy1 = (ih * ++i) / n;
845 pkg->y0 = iy0; pkg->y1 = iy1;
850 LoadClient* HistStripeEngine::new_client()
852 return new HistStripeUnit(this, plugin);
855 LoadPackage* HistStripeEngine::new_package()
857 return new HistStripePackage();
860 void HistStripeEngine::process_packages(int operation)
862 this->operation = operation;
863 LoadServer::process_packages();
868 HistogramPackage::HistogramPackage()
873 HistogramUnit::HistogramUnit(HistogramEngine *server,
874 HistogramMain *plugin)
877 this->plugin = plugin;
878 this->server = server;
879 for(int i = 0; i < HISTOGRAM_MODES; i++)
880 accum[i] = new int[HISTOGRAM_SLOTS];
883 HistogramUnit::~HistogramUnit()
885 for(int i = 0; i < HISTOGRAM_MODES; i++)
889 void HistogramUnit::process_package(LoadPackage *package)
891 HistogramPackage *pkg = (HistogramPackage*)package;
892 switch( server->operation ) {
893 case HistogramEngine::HISTOGRAM: {
894 int do_value = server->do_value;
895 const int hmin = HISTOGRAM_MIN * 0xffff / 100;
896 const int slots1 = HISTOGRAM_SLOTS-1;
898 #define HISTOGRAM_HEAD(type) { \
899 type **rows = (type**)data->get_rows(); \
900 for( int iy=pkg->start; iy<pkg->end; ++iy ) { \
901 type *row = rows[iy]; \
902 for( int ix=0; ix<w; ++ix ) {
904 #define HISTOGRAM_TAIL(components) \
906 r_out = preview_r[bclip(r, 0, 0xffff)]; \
907 g_out = preview_g[bclip(g, 0, 0xffff)]; \
908 b_out = preview_b[bclip(b, 0, 0xffff)]; \
909 /* v = (r * 76 + g * 150 + b * 29) >> 8; */ \
910 /* Value takes the maximum of the output RGB values */ \
911 v = MAX(r_out, g_out); v = MAX(v, b_out); \
912 ++accum_v[bclip(v -= hmin, 0, slots1)]; \
915 ++accum_r[bclip(r -= hmin, 0, slots1)]; \
916 ++accum_g[bclip(g -= hmin, 0, slots1)]; \
917 ++accum_b[bclip(b -= hmin, 0, slots1)]; \
923 VFrame *data = server->data;
924 int w = data->get_w();
925 //int h = data->get_h();
926 int *accum_r = accum[HISTOGRAM_RED];
927 int *accum_g = accum[HISTOGRAM_GREEN];
928 int *accum_b = accum[HISTOGRAM_BLUE];
929 int *accum_v = accum[HISTOGRAM_VALUE];
930 int32_t r, g, b, y, u, v;
931 int r_out, g_out, b_out;
932 int *preview_r = plugin->preview_lookup[HISTOGRAM_RED];
933 int *preview_g = plugin->preview_lookup[HISTOGRAM_GREEN];
934 int *preview_b = plugin->preview_lookup[HISTOGRAM_BLUE];
936 switch( data->get_color_model() ) {
938 HISTOGRAM_HEAD(unsigned char)
939 r = (row[0] << 8) | row[0];
940 g = (row[1] << 8) | row[1];
941 b = (row[2] << 8) | row[2];
945 HISTOGRAM_HEAD(float)
946 r = (int)(row[0] * 0xffff);
947 g = (int)(row[1] * 0xffff);
948 b = (int)(row[2] * 0xffff);
952 HISTOGRAM_HEAD(unsigned char)
953 y = (row[0] << 8) | row[0];
954 u = (row[1] << 8) | row[1];
955 v = (row[2] << 8) | row[2];
956 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
960 HISTOGRAM_HEAD(unsigned char)
961 r = (row[0] << 8) | row[0];
962 g = (row[1] << 8) | row[1];
963 b = (row[2] << 8) | row[2];
967 HISTOGRAM_HEAD(float)
968 r = (int)(row[0] * 0xffff);
969 g = (int)(row[1] * 0xffff);
970 b = (int)(row[2] * 0xffff);
974 HISTOGRAM_HEAD(unsigned char)
975 y = (row[0] << 8) | row[0];
976 u = (row[1] << 8) | row[1];
977 v = (row[2] << 8) | row[2];
978 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
982 HISTOGRAM_HEAD(uint16_t)
989 HISTOGRAM_HEAD(uint16_t)
993 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
996 case BC_RGBA16161616:
997 HISTOGRAM_HEAD(uint16_t)
1003 case BC_YUVA16161616:
1004 HISTOGRAM_HEAD(uint16_t)
1008 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1013 case HistogramEngine::APPLY: {
1015 #define PROCESS(type, components) { \
1016 type **rows = (type**)input->get_rows(); \
1017 for( int iy=pkg->start; iy<pkg->end; ++iy ) { \
1018 type *row = rows[iy]; \
1019 for( int ix=0; ix<w; ++ix ) { \
1020 if( plugin->config.split && ((ix + (iy*w)/h) < w) ) \
1022 row[0] = lookup_r[row[0]]; \
1023 row[1] = lookup_g[row[1]]; \
1024 row[2] = lookup_b[row[2]]; \
1025 row += components; \
1030 #define PROCESS_YUV(type, components, max) { \
1031 type **rows = (type**)input->get_rows(); \
1032 for( int iy=pkg->start; iy<pkg->end; ++iy ) { \
1033 type *row = rows[iy]; \
1034 for( int ix=0; ix<w; ++ix ) { \
1035 if( plugin->config.split && ((ix + (iy*w)/h) < w) ) \
1037 if( max == 0xff ) { /* Convert to 16 bit RGB */ \
1038 y = (row[0] << 8) | row[0]; \
1039 u = (row[1] << 8) | row[1]; \
1040 v = (row[2] << 8) | row[2]; \
1047 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
1048 /* Look up in RGB domain */ \
1052 /* Convert to 16 bit YUV */ \
1053 YUV::yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
1054 if( max == 0xff ) { \
1064 row += components; \
1069 #define PROCESS_FLOAT(components) { \
1070 float **rows = (float**)input->get_rows(); \
1071 for( int iy=pkg->start; iy<pkg->end; ++iy ) { \
1072 float *row = rows[iy]; \
1073 for( int ix=0; ix<w; ++ix ) { \
1074 if( plugin->config.split && ((ix + (iy*w)/h) < w) ) \
1076 float fr = row[0]; \
1077 float fg = row[1]; \
1078 float fb = row[2]; \
1079 row[0] = plugin->calculate_level(fr, HISTOGRAM_RED, 1); \
1080 row[1] = plugin->calculate_level(fg, HISTOGRAM_GREEN, 1); \
1081 row[2] = plugin->calculate_level(fb, HISTOGRAM_BLUE, 1); \
1082 row += components; \
1087 VFrame *input = plugin->input;
1088 //VFrame *output = plugin->output;
1089 int w = input->get_w();
1090 int h = input->get_h();
1091 int *lookup_r = plugin->lookup[0];
1092 int *lookup_g = plugin->lookup[1];
1093 int *lookup_b = plugin->lookup[2];
1094 int r, g, b, y, u, v;
1095 switch( input->get_color_model() ) {
1097 PROCESS(unsigned char, 3)
1103 PROCESS(unsigned char, 4)
1109 PROCESS(uint16_t, 3)
1111 case BC_RGBA16161616:
1112 PROCESS(uint16_t, 4)
1115 PROCESS_YUV(unsigned char, 3, 0xff)
1118 PROCESS_YUV(unsigned char, 4, 0xff)
1121 PROCESS_YUV(uint16_t, 3, 0xffff)
1123 case BC_YUVA16161616:
1124 PROCESS_YUV(uint16_t, 4, 0xffff)
1132 HistogramEngine::HistogramEngine(HistogramMain *plugin,
1133 int total_clients, int total_packages)
1134 : LoadServer(total_clients, total_packages)
1136 this->plugin = plugin;
1139 void HistogramEngine::init_packages()
1143 total_size = data->get_h();
1146 total_size = data->get_h();
1151 for( int i=0,n=get_total_packages(); i<n; ++i ) {
1152 HistogramPackage *package = (HistogramPackage*)get_package(i);
1153 package->start = start;
1154 package->end = total_size * (i+1)/n;
1155 start = package->end;
1158 // Initialize clients here in case some don't get run.
1159 for( int i=0,n=get_total_clients(); i<n; ++i ) {
1160 HistogramUnit *unit = (HistogramUnit*)get_client(i);
1161 for( int j=0; j<HISTOGRAM_MODES; ++j )
1162 bzero(unit->accum[j], sizeof(int) * HISTOGRAM_SLOTS);
1166 LoadClient* HistogramEngine::new_client()
1168 return new HistogramUnit(this, plugin);
1171 LoadPackage* HistogramEngine::new_package()
1173 return new HistogramPackage;
1176 void HistogramEngine::process_packages(int operation, VFrame *data, int do_value)
1179 this->operation = operation;
1180 this->do_value = do_value;
1181 LoadServer::process_packages();