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;
62 REGISTER_PLUGIN(HistogramMain)
72 HistogramMain::HistogramMain(PluginServer *server)
73 : PluginVClient(server)
78 for(int i = 0; i < HISTOGRAM_MODES; i++)
82 preview_lookup[i] = 0;
85 mode = HISTOGRAM_VALUE;
97 HistogramMain::~HistogramMain()
100 for(int i = 0; i < HISTOGRAM_MODES;i++)
104 delete [] preview_lookup[i];
107 delete stripe_engine;
111 const char* HistogramMain::plugin_title() { return N_("Histogram"); }
112 int HistogramMain::is_realtime() { return 1; }
116 NEW_WINDOW_MACRO(HistogramMain, HistogramWindow)
118 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
120 void HistogramMain::render_gui(void *data)
124 // Process just the RGB values to determine the automatic points or
125 // all the points if manual
126 if(!config.automatic)
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();
137 calculate_histogram((VFrame*)data, !config.automatic);
142 calculate_automatic((VFrame*)data);
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();
153 // Need a second pass to get the luminance values.
154 calculate_histogram((VFrame*)data, 1);
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,
164 ((HistogramWindow*)thread->window)->unlock_window();
168 void HistogramMain::update_gui()
172 ((HistogramWindow*)thread->window)->lock_window("HistogramMain::update_gui");
173 int reconfigure = load_configuration();
176 ((HistogramWindow*)thread->window)->update(1,
181 ((HistogramWindow*)thread->window)->unlock_window();
188 void HistogramMain::save_data(KeyFrame *keyframe)
192 // cause data to be stored directly in text
193 output.set_shared_output(keyframe->xbuf);
194 output.tag.set_title("HISTOGRAM");
196 char string[BCTEXTLEN];
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);
209 for(int i = 0; i < HISTOGRAM_MODES; i++)
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]);
225 output.tag.set_title("/HISTOGRAM");
227 output.append_newline();
228 output.terminate_string();
231 void HistogramMain::read_data(KeyFrame *keyframe)
235 input.set_shared_input(keyframe->xbuf);
242 result = input.read_tag();
246 if(input.tag.title_is("HISTOGRAM"))
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);
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);
263 char string[BCTEXTLEN];
264 for(int i = 0; i < HISTOGRAM_MODES; i++)
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]);
273 if(i == HISTOGRAM_VALUE || !config.automatic)
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]);
280 //printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
290 float HistogramMain::calculate_level(float input,
296 // Scale to input range
297 if(!EQUIV(config.high_input[mode], config.low_input[mode]))
299 output = input < config.low_input[mode] ? 0 :
300 (input - config.low_input[mode]) /
301 (config.high_input[mode] - config.low_input[mode]);
310 if(!EQUIV(config.gamma[mode], 0))
312 output = pow(output, 1.0 / config.gamma[mode]);
313 CLAMP(output, 0, 1.0);
317 if(use_value && mode != HISTOGRAM_VALUE)
319 output = calculate_level(output, HISTOGRAM_VALUE, 0);
325 // scale to output range
326 if(!EQUIV(config.low_output[mode], config.high_output[mode]))
328 output = output * (config.high_output[mode] - config.low_output[mode]) +
329 config.low_output[mode];
332 CLAMP(output, 0, 1.0);
339 void HistogramMain::calculate_histogram(VFrame *data, int do_value)
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);
350 for(int i = 0; i < HISTOGRAM_MODES; i++)
351 accum[i] = new int[HISTOGRAM_SLOTS];
354 engine->process_packages(HistogramEngine::HISTOGRAM, data, do_value);
356 for(int i = 0; i < engine->get_total_clients(); i++)
358 HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
362 for(int j = 0; j < HISTOGRAM_MODES; j++)
364 memcpy(accum[j], unit->accum[j], sizeof(int) * HISTOGRAM_SLOTS);
369 for(int j = 0; j < HISTOGRAM_MODES; j++)
372 int *in = unit->accum[j];
373 for(int k = 0; k < HISTOGRAM_SLOTS; k++)
379 // Remove top and bottom from calculations. Doesn't work in high
380 // precision colormodels.
381 for(int i = 0; i < HISTOGRAM_MODES; i++)
384 accum[i][HISTOGRAM_SLOTS - 1] = 0;
389 void HistogramMain::calculate_automatic(VFrame *data)
391 calculate_histogram(data, 0);
392 config.reset_points(1);
395 for(int i = 0; i < 3; i++)
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);
402 float max_level = 1.0;
403 float min_level = 0.0;
405 // Get histogram slot above threshold of pixels
406 for(int j = 0; j < HISTOGRAM_SLOTS; j++)
409 if(total >= threshold)
411 max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
416 // Get slot below 99% of pixels
418 for(int j = HISTOGRAM_SLOTS - 1; j >= 0; j--)
421 if(total >= threshold)
423 min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
429 config.low_input[i] = min_level;
430 config.high_input[i] = max_level;
438 int HistogramMain::calculate_use_opengl()
440 // glHistogram doesn't work.
441 int result = get_use_opengl() &&
443 (!config.plot || !gui_open());
448 int HistogramMain::process_buffer(VFrame *frame,
449 int64_t start_position,
452 int need_reconfigure = load_configuration();
453 int use_opengl = calculate_use_opengl();
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;
461 engine = new HistogramEngine(this, cpus, cpus);
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() ) ) {
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);
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");
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);
497 if( progress && timer.get_difference() > 100 ) {
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;
505 if( progress && !gui_open() ) {
506 progress->stop_progress();
507 delete progress; progress = 0;
510 read_frame(temp, 0, start_position, frame_rate, use_opengl);
511 stripe_engine->process_packages(ADD_FFRMS);
512 frame->transfer_from(temp);
514 progress->stop_progress();
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);
529 read_frame(frame, 0, start_position, frame_rate, use_opengl);
531 // if to plot histogram
532 if(config.plot) send_render_gui(frame);
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
539 if(need_reconfigure ||
543 // Calculate new curves
546 calculate_automatic(input);
550 // Generate transfer tables with value function for integer colormodels.
551 for(int i = 0; i < 3; i++)
552 tabulate_curve(i, 1);
555 // printf("HistogramMain::process_buffer %d %f %f %f %f %f %f %f %f %f\n",
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]);
567 // Apply histogram in hardware
568 if(use_opengl) return run_opengl();
571 engine->process_packages(HistogramEngine::APPLY, input, 0);
575 void HistogramMain::tabulate_curve(int subscript, int use_value)
578 if(!lookup[subscript])
579 lookup[subscript] = new int[HISTOGRAM_SLOTS];
580 if(!preview_lookup[subscript])
581 preview_lookup[subscript] = new int[HISTOGRAM_SLOTS];
583 //printf("HistogramMain::tabulate_curve %d input=%p\n", __LINE__, input);
586 // Generate lookup tables for integer colormodels
589 switch(input->get_color_model())
593 for(i = 0; i < 0x100; i++)
595 lookup[subscript][i] =
596 (int)(calculate_level((float)i / 0xff, subscript, use_value) *
598 CLAMP(lookup[subscript][i], 0, 0xff);
601 // All other integer colormodels are converted to 16 bit RGB
603 for(i = 0; i < 0x10000; i++)
605 lookup[subscript][i] =
606 (int)(calculate_level((float)i / 0xffff, subscript, use_value) *
608 CLAMP(lookup[subscript][i], 0, 0xffff);
610 // for(i = 0; i < 0x100; i++)
612 // if(subscript == HISTOGRAM_BLUE) printf("%d ", lookup[subscript][i * 0x100]);
614 // if(subscript == HISTOGRAM_BLUE) printf("\n");
620 // Lookup table for preview only used for GUI
623 for(i = 0; i < 0x10000; i++)
625 preview_lookup[subscript][i] =
626 (int)(calculate_level((float)i / 0xffff, subscript, use_value) *
628 CLAMP(preview_lookup[subscript][i], 0, 0xffff);
633 int HistogramMain::handle_opengl()
636 // Functions to get pixel from either previous effect or texture
637 static const char *histogram_get_pixel1 =
638 "vec4 histogram_get_pixel()\n"
640 " return gl_FragColor;\n"
643 static const char *histogram_get_pixel2 =
644 "uniform sampler2D tex;\n"
645 "vec4 histogram_get_pixel()\n"
647 " return texture2D(tex, gl_TexCoord[0].st);\n"
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"
658 " float temp = 0.0;\n";
660 static const char *get_rgb_frag =
661 " vec4 pixel = histogram_get_pixel();\n";
663 static const char *get_yuv_frag =
664 " vec4 pixel = histogram_get_pixel();\n"
665 YUV_TO_RGB_FRAG("pixel");
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"
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";
690 static const char *put_rgb_frag =
691 " gl_FragColor = pixel;\n"
694 static const char *put_yuv_frag =
695 RGB_TO_YUV_FRAG("pixel")
696 " gl_FragColor = pixel;\n"
701 get_output()->to_texture();
702 get_output()->enable_opengl();
704 const char *shader_stack[16];
705 memset(shader_stack,0, sizeof(shader_stack));
706 int current_shader = 0;
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;
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")))
721 aggregate_interpolation = 1;
723 aggregate_colorbalance = 1;
726 if(!strcmp(get_output()->get_prev_effect(1), _("Gamma")) &&
727 !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
730 aggregate_colorbalance = 1;
733 if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
734 !strcmp(get_output()->get_prev_effect(0), _("Gamma")))
736 aggregate_interpolation = 1;
740 if(!strcmp(get_output()->get_prev_effect(1), _("Interpolate Pixels")) &&
741 !strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
743 aggregate_interpolation = 1;
744 aggregate_colorbalance = 1;
747 if(!strcmp(get_output()->get_prev_effect(0), _("Interpolate Pixels")))
748 aggregate_interpolation = 1;
750 if(!strcmp(get_output()->get_prev_effect(0), _("Gamma")))
753 if(!strcmp(get_output()->get_prev_effect(0), _("Color Balance")))
754 aggregate_colorbalance = 1;
756 // The order of processing is fixed by this sequence
757 if(aggregate_interpolation)
758 INTERPOLATE_COMPILE(shader_stack, current_shader);
761 GAMMA_COMPILE(shader_stack, current_shader,
762 aggregate_interpolation);
764 if(aggregate_colorbalance)
765 COLORBALANCE_COMPILE(shader_stack, current_shader,
766 aggregate_interpolation || aggregate_gamma);
768 shader_stack[current_shader++] =
769 aggregate_interpolation || aggregate_gamma || aggregate_colorbalance ?
770 histogram_get_pixel1 : histogram_get_pixel2;
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;
779 shader_stack[current_shader] = 0;
780 unsigned int shader = VFrame::make_shader(shader_stack);
782 // printf("HistogramMain::handle_opengl %d %d %d %d shader=%d\n",
783 // aggregate_interpolation,
785 // aggregate_colorbalance,
793 float output_scale[4];
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]);
802 for(int i = 0; i < HISTOGRAM_MODES; i++)
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];
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);
826 get_output()->init_screen();
827 get_output()->bind_texture(0);
831 // Draw the affected half
834 glBegin(GL_TRIANGLES);
835 glNormal3f(0, 0, 1.0);
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);
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);
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);
855 get_output()->draw_texture();
860 // Draw the unaffected half
863 glBegin(GL_TRIANGLES);
864 glNormal3f(0, 0, 1.0);
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);
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);
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);
884 get_output()->set_opengl_state(VFrame::SCREEN);
890 HistStripePackage::HistStripePackage()
895 HistStripeUnit::HistStripeUnit(HistStripeEngine *server, HistogramMain *plugin)
898 this->plugin = plugin;
899 this->server = server;
902 void HistStripeUnit::process_package(LoadPackage *package)
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 ) {
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;
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;
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;
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;
970 HistStripeEngine::HistStripeEngine(HistogramMain *plugin,
971 int total_clients, int total_packages)
972 : LoadServer(total_clients, total_packages)
974 this->plugin = plugin;
976 void HistStripeEngine::init_packages()
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;
987 LoadClient* HistStripeEngine::new_client()
989 return new HistStripeUnit(this, plugin);
992 LoadPackage* HistStripeEngine::new_package()
994 return new HistStripePackage();
997 void HistStripeEngine::process_packages(int operation)
999 this->operation = operation;
1000 LoadServer::process_packages();
1005 HistogramPackage::HistogramPackage()
1010 HistogramUnit::HistogramUnit(HistogramEngine *server,
1011 HistogramMain *plugin)
1012 : LoadClient(server)
1014 this->plugin = plugin;
1015 this->server = server;
1016 for(int i = 0; i < HISTOGRAM_MODES; i++)
1017 accum[i] = new int[HISTOGRAM_SLOTS];
1020 HistogramUnit::~HistogramUnit()
1022 for(int i = 0; i < HISTOGRAM_MODES; i++)
1026 void HistogramUnit::process_package(LoadPackage *package)
1028 HistogramPackage *pkg = (HistogramPackage*)package;
1030 if(server->operation == HistogramEngine::HISTOGRAM)
1032 int do_value = server->do_value;
1035 #define HISTOGRAM_HEAD(type) \
1037 for(int i = pkg->start; i < pkg->end; i++) \
1039 type *row = (type*)data->get_rows()[i]; \
1040 for(int j = 0; j < w; j++) \
1043 #define HISTOGRAM_TAIL(components) \
1044 /* Value takes the maximum of the output RGB values */ \
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); \
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); \
1070 row += components; \
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];
1091 switch(data->get_color_model())
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];
1101 HISTOGRAM_HEAD(float)
1102 r = (int)(row[0] * 0xffff);
1103 g = (int)(row[1] * 0xffff);
1104 b = (int)(row[2] * 0xffff);
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);
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];
1123 HISTOGRAM_HEAD(float)
1124 r = (int)(row[0] * 0xffff);
1125 g = (int)(row[1] * 0xffff);
1126 b = (int)(row[2] * 0xffff);
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);
1138 HISTOGRAM_HEAD(uint16_t)
1145 HISTOGRAM_HEAD(uint16_t)
1149 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1152 case BC_RGBA16161616:
1153 HISTOGRAM_HEAD(uint16_t)
1159 case BC_YUVA16161616:
1160 HISTOGRAM_HEAD(uint16_t)
1164 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1170 if(server->operation == HistogramEngine::APPLY)
1175 #define PROCESS(type, components) \
1177 for(int i = pkg->start; i < pkg->end; i++) \
1179 type *row = (type*)input->get_rows()[i]; \
1180 for(int j = 0; j < w; j++) \
1182 if ( plugin->config.split && ((j + i * w / h) < w) ) \
1184 row[0] = lookup_r[row[0]]; \
1185 row[1] = lookup_g[row[1]]; \
1186 row[2] = lookup_b[row[2]]; \
1187 row += components; \
1192 #define PROCESS_YUV(type, components, max) \
1194 for(int i = pkg->start; i < pkg->end; i++) \
1196 type *row = (type*)input->get_rows()[i]; \
1197 for(int j = 0; j < w; j++) \
1199 if ( plugin->config.split && ((j + i * w / h) < w) ) \
1201 /* Convert to 16 bit RGB */ \
1204 y = (row[0] << 8) | row[0]; \
1205 u = (row[1] << 8) | row[1]; \
1206 v = (row[2] << 8) | row[2]; \
1215 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
1217 /* Look up in RGB domain */ \
1222 /* Convert to 16 bit YUV */ \
1223 YUV::yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
1237 row += components; \
1242 #define PROCESS_FLOAT(components) \
1244 for(int i = pkg->start; i < pkg->end; i++) \
1246 float *row = (float*)input->get_rows()[i]; \
1247 for(int j = 0; j < w; j++) \
1249 if ( plugin->config.split && ((j + i * w / h) < w) ) \
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); \
1263 row += components; \
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())
1280 PROCESS(unsigned char, 3)
1286 PROCESS(unsigned char, 4)
1292 PROCESS(uint16_t, 3)
1294 case BC_RGBA16161616:
1295 PROCESS(uint16_t, 4)
1298 PROCESS_YUV(unsigned char, 3, 0xff)
1301 PROCESS_YUV(unsigned char, 4, 0xff)
1304 PROCESS_YUV(uint16_t, 3, 0xffff)
1306 case BC_YUVA16161616:
1307 PROCESS_YUV(uint16_t, 4, 0xffff)
1318 HistogramEngine::HistogramEngine(HistogramMain *plugin,
1321 : LoadServer(total_clients, total_packages)
1323 this->plugin = plugin;
1326 void HistogramEngine::init_packages()
1331 total_size = data->get_h();
1334 total_size = data->get_h();
1339 //int package_size = (int)((float)total_size / get_total_packages() + 1);
1342 for(int i = 0; i < get_total_packages(); i++)
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();
1349 // Initialize clients here in case some don't get run.
1350 for(int i = 0; i < get_total_clients(); i++)
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);
1359 LoadClient* HistogramEngine::new_client()
1361 return new HistogramUnit(this, plugin);
1364 LoadPackage* HistogramEngine::new_package()
1366 return new HistogramPackage;
1369 void HistogramEngine::process_packages(int operation, VFrame *data, int do_value)
1372 this->operation = operation;
1373 this->do_value = do_value;
1374 LoadServer::process_packages();