5 #include "bcdisplayinfo.h"
11 #include "loadbalance.h"
12 #include "max_picon_png.h"
13 #include "mid_picon_png.h"
14 #include "min_picon_png.h"
15 #include "picon_png.h"
16 #include "../libcolors/plugincolors.h"
17 #include "pluginvclient.h"
22 #define _(String) gettext(String)
23 #define gettext_noop(String) String
24 #define N_(String) gettext_noop (String)
28 class HistogramEngine;
29 class HistogramWindow;
32 #define HISTOGRAM_RED 0
33 #define HISTOGRAM_GREEN 1
34 #define HISTOGRAM_BLUE 2
35 #define HISTOGRAM_ALPHA 3
36 #define HISTOGRAM_VALUE 4
39 #define HISTOGRAM_RANGE 0x10000
41 #define THRESHOLD_SCALE 1000
48 int equivalent(HistogramConfig &that);
49 void copy_from(HistogramConfig &that);
50 void interpolate(HistogramConfig &prev,
51 HistogramConfig &next,
54 int64_t current_frame);
55 void reset(int do_mode);
69 class HistogramSlider : public BC_SubWindow
72 HistogramSlider(HistogramMain *plugin,
81 int button_press_event();
82 int button_release_event();
83 int cursor_motion_event();
96 HistogramMain *plugin;
100 class HistogramAuto : public BC_CheckBox
103 HistogramAuto(HistogramMain *plugin,
107 HistogramMain *plugin;
110 class HistogramMode : public BC_Radial
113 HistogramMode(HistogramMain *plugin,
119 HistogramMain *plugin;
123 class HistogramReset : public BC_GenericButton
126 HistogramReset(HistogramMain *plugin,
130 HistogramMain *plugin;
133 class HistogramText : public BC_TumbleTextBox
136 HistogramText(HistogramMain *plugin,
137 HistogramWindow *gui,
142 HistogramMain *plugin;
146 class HistogramWindow : public BC_Window
149 HistogramWindow(HistogramMain *plugin, int x, int y);
152 int create_objects();
154 void update(int do_input);
156 void update_canvas();
158 void update_output();
160 HistogramSlider *input, *output;
161 HistogramAuto *automatic;
162 HistogramMode *mode_v, *mode_r, *mode_g, *mode_b, *mode_a;
163 HistogramText *input_min;
164 HistogramText *input_mid;
165 HistogramText *input_max;
166 HistogramText *output_min;
167 HistogramText *output_max;
168 HistogramText *threshold;
169 BC_SubWindow *canvas;
170 HistogramMain *plugin;
171 BC_Pixmap *max_picon, *mid_picon, *min_picon;
176 PLUGIN_THREAD_HEADER(HistogramMain, HistogramThread, HistogramWindow)
179 class HistogramMain : public PluginVClient
182 HistogramMain(PluginServer *server);
185 int process_realtime(VFrame *input_ptr, VFrame *output_ptr);
189 void save_data(KeyFrame *keyframe);
190 void read_data(KeyFrame *keyframe);
192 void render_gui(void *data);
193 PLUGIN_CLASS_MEMBERS(HistogramConfig, HistogramThread)
195 // Convert input to input curve
196 float calculate_curve(float input, int mode);
197 // Calculate automatic settings
198 void calculate_automatic(VFrame *data);
199 // Calculate histogram
200 void calculate_histogram(VFrame *data);
205 VFrame *input, *output;
206 HistogramEngine *engine;
211 class HistogramPackage : public LoadPackage
218 class HistogramUnit : public LoadClient
221 HistogramUnit(HistogramEngine *server, HistogramMain *plugin);
223 void process_package(LoadPackage *package);
224 HistogramEngine *server;
225 HistogramMain *plugin;
229 class HistogramEngine : public LoadServer
232 HistogramEngine(HistogramMain *plugin,
235 void process_packages(int operation, VFrame *data);
236 void init_packages();
237 LoadClient* new_client();
238 LoadPackage* new_package();
239 HistogramMain *plugin;
269 REGISTER_PLUGIN(HistogramMain)
273 HistogramConfig::HistogramConfig()
278 void HistogramConfig::reset(int do_mode)
280 for(int i = 0; i < 5; i++)
283 input_mid[i] = 0x8000;
284 input_max[i] = 0xffff;
286 output_max[i] = 0xffff;
290 mode = HISTOGRAM_VALUE;
296 int HistogramConfig::equivalent(HistogramConfig &that)
298 for(int i = 0; i < 5; i++)
300 if(input_min[i] != that.input_min[i] ||
301 input_mid[i] != that.input_mid[i] ||
302 input_max[i] != that.input_max[i] ||
303 output_min[i] != that.output_min[i] ||
304 output_max[i] != that.output_max[i]) return 0;
307 if(automatic != that.automatic ||
309 threshold != that.threshold) return 0;
314 void HistogramConfig::copy_from(HistogramConfig &that)
316 for(int i = 0; i < 5; i++)
318 input_min[i] = that.input_min[i];
319 input_mid[i] = that.input_mid[i];
320 input_max[i] = that.input_max[i];
321 output_min[i] = that.output_min[i];
322 output_max[i] = that.output_max[i];
325 automatic = that.automatic;
327 threshold = that.threshold;
330 void HistogramConfig::interpolate(HistogramConfig &prev,
331 HistogramConfig &next,
334 int64_t current_frame)
336 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
337 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
339 for(int i = 0; i < 5; i++)
341 input_min[i] = (int)(prev.input_min[i] * prev_scale + next.input_min[i] * next_scale);
342 input_mid[i] = (int)(prev.input_mid[i] * prev_scale + next.input_mid[i] * next_scale);
343 input_max[i] = (int)(prev.input_max[i] * prev_scale + next.input_max[i] * next_scale);
344 output_min[i] = (int)(prev.output_min[i] * prev_scale + next.output_min[i] * next_scale);
345 output_max[i] = (int)(prev.output_max[i] * prev_scale + next.output_max[i] * next_scale);
347 threshold = (int)(prev.threshold * prev_scale + next.threshold * next_scale);
348 automatic = prev.automatic;
358 PLUGIN_THREAD_OBJECT(HistogramMain, HistogramThread, HistogramWindow)
362 HistogramWindow::HistogramWindow(HistogramMain *plugin, int x, int y)
363 : BC_Window(plugin->gui_string,
373 this->plugin = plugin;
376 HistogramWindow::~HistogramWindow()
380 static VFrame max_picon_image(max_picon_png);
381 static VFrame mid_picon_image(mid_picon_png);
382 static VFrame min_picon_image(min_picon_png);
384 int HistogramWindow::create_objects()
386 int x = 10, y = 10, x1 = 10;
387 int subscript = plugin->config.mode;
389 max_picon = new BC_Pixmap(this, &max_picon_image);
390 mid_picon = new BC_Pixmap(this, &mid_picon_image);
391 min_picon = new BC_Pixmap(this, &min_picon_image);
392 add_subwindow(mode_v = new HistogramMode(plugin,
398 add_subwindow(mode_r = new HistogramMode(plugin,
404 add_subwindow(mode_g = new HistogramMode(plugin,
410 add_subwindow(mode_b = new HistogramMode(plugin,
416 add_subwindow(mode_a = new HistogramMode(plugin,
424 add_subwindow(new BC_Title(x, y, _("Input min:")));
426 input_min = new HistogramText(plugin,
430 &plugin->config.input_min[subscript]);
431 input_min->create_objects();
433 add_subwindow(new BC_Title(x, y, _("Mid:")));
435 input_mid = new HistogramText(plugin,
439 &plugin->config.input_mid[subscript]);
440 input_mid->create_objects();
441 input_mid->update((int64_t)plugin->config.input_mid[subscript]);
443 add_subwindow(new BC_Title(x, y, _("Max:")));
445 input_max = new HistogramText(plugin,
449 &plugin->config.input_max[subscript]);
450 input_max->create_objects();
454 add_subwindow(canvas = new BC_SubWindow(x,
460 y += canvas->get_h() + 10;
461 add_subwindow(input = new HistogramSlider(plugin,
470 y += input->get_h() + 10;
471 add_subwindow(new BC_Title(x, y, _("Output min:")));
473 output_min = new HistogramText(plugin,
477 &plugin->config.output_min[subscript]);
478 output_min->create_objects();
480 add_subwindow(new BC_Title(x, y, _("Max:")));
482 output_max = new HistogramText(plugin,
486 &plugin->config.output_max[subscript]);
487 output_max->create_objects();
494 add_subwindow(output = new HistogramSlider(plugin,
505 add_subwindow(automatic = new HistogramAuto(plugin,
510 add_subwindow(new HistogramReset(plugin,
514 add_subwindow(new BC_Title(x, y, _("Threshold:")));
516 threshold = new HistogramText(plugin,
520 &plugin->config.threshold);
521 threshold->create_objects();
528 WINDOW_CLOSE_EVENT(HistogramWindow)
530 void HistogramWindow::update(int do_input)
532 automatic->update(plugin->config.automatic);
533 threshold->update((int64_t)plugin->config.threshold);
536 if(do_input) update_input();
540 void HistogramWindow::update_input()
542 int subscript = plugin->config.mode;
544 input_min->update((int64_t)plugin->config.input_min[subscript]);
545 input_mid->update((int64_t)plugin->config.input_mid[subscript]);
546 input_max->update((int64_t)plugin->config.input_max[subscript]);
549 void HistogramWindow::update_output()
551 int subscript = plugin->config.mode;
553 output_min->update((int64_t)plugin->config.output_min[subscript]);
554 output_max->update((int64_t)plugin->config.output_max[subscript]);
557 void HistogramWindow::update_mode()
559 mode_v->update(plugin->config.mode == HISTOGRAM_VALUE ? 1 : 0);
560 mode_r->update(plugin->config.mode == HISTOGRAM_RED ? 1 : 0);
561 mode_g->update(plugin->config.mode == HISTOGRAM_GREEN ? 1 : 0);
562 mode_b->update(plugin->config.mode == HISTOGRAM_BLUE ? 1 : 0);
563 mode_a->update(plugin->config.mode == HISTOGRAM_ALPHA ? 1 : 0);
564 input_min->output = &plugin->config.input_min[plugin->config.mode];
565 input_mid->output = &plugin->config.input_mid[plugin->config.mode];
566 input_max->output = &plugin->config.input_max[plugin->config.mode];
567 output_min->output = &plugin->config.output_min[plugin->config.mode];
568 output_max->output = &plugin->config.output_max[plugin->config.mode];
571 void HistogramWindow::update_canvas()
573 int64_t *accum = plugin->accum[plugin->config.mode];
574 int canvas_w = canvas->get_w();
575 int canvas_h = canvas->get_h();
576 int accum_per_canvas_i = HISTOGRAM_RANGE / canvas_w + 1;
577 float accum_per_canvas_f = (float)HISTOGRAM_RANGE / canvas_w;
580 for(int i = 0; i < HISTOGRAM_RANGE; i++)
582 if(accum[i] > normalize) normalize = accum[i];
588 for(int i = 0; i < canvas_w; i++)
590 int accum_start = (int)(accum_per_canvas_f * i);
591 int accum_end = accum_start + accum_per_canvas_i;
593 for(int j = accum_start; j < accum_end; j++)
595 max = MAX(accum[j], max);
597 //printf("HistogramWindow::update_canvas 1 %d %d\n", i, max);
599 // max = max * canvas_h / normalize;
600 max = (int)(log(max) / log(normalize) * canvas_h);
603 canvas->set_color(0xffffff);
604 canvas->draw_line(i, 0, i, canvas_h - max);
605 canvas->set_color(0x000000);
606 canvas->draw_line(i, canvas_h - max, i, canvas_h);
611 canvas->set_color(0xffffff);
612 canvas->draw_box(0, 0, canvas_w, canvas_h);
615 canvas->set_color(0x00ff00);
617 for(int i = 0; i < canvas_w; i++)
619 int y2 = canvas_h - (int)(plugin->calculate_curve((float)i / canvas_w * (HISTOGRAM_RANGE - 1),
620 plugin->config.mode) * canvas_h / (HISTOGRAM_RANGE - 1));
623 canvas->draw_line(i - 1, y1, i, y2);
638 HistogramReset::HistogramReset(HistogramMain *plugin,
641 : BC_GenericButton(x, y, _("Reset"))
643 this->plugin = plugin;
645 int HistogramReset::handle_event()
647 plugin->config.reset(0);
648 plugin->thread->window->update(1);
649 plugin->send_configure_change();
661 HistogramSlider::HistogramSlider(HistogramMain *plugin,
662 HistogramWindow *gui,
668 : BC_SubWindow(x, y, w, h)
670 this->plugin = plugin;
672 this->is_input = is_input;
676 int HistogramSlider::button_press_event()
678 if(is_event_win() && cursor_inside())
680 int subscript = plugin->config.mode;
685 int half_h = get_h() / 2;
689 int x1 = (int)(plugin->config.input_mid[subscript] * w / 0xffff) -
690 gui->mid_picon->get_w() / 2;
691 int x2 = x1 + gui->mid_picon->get_w();
692 if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
693 get_cursor_y() >= half_h && get_cursor_y() < h)
695 operation = DRAG_MID_INPUT;
699 if(operation == NONE)
703 int x1 = (int)(plugin->config.input_min[subscript] * w / 0xffff) -
704 gui->mid_picon->get_w() / 2;
705 int x2 = x1 + gui->mid_picon->get_w();
706 if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
707 get_cursor_y() >= half_h && get_cursor_y() < h)
709 operation = DRAG_MIN_INPUT;
714 int x1 = (int)(plugin->config.output_min[subscript] * w / 0xffff) -
715 gui->mid_picon->get_w() / 2;
716 int x2 = x1 + gui->mid_picon->get_w();
717 if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
718 get_cursor_y() >= half_h && get_cursor_y() < h)
720 operation = DRAG_MIN_OUTPUT;
725 if(operation == NONE)
729 int x1 = (int)(plugin->config.input_max[subscript] * w / 0xffff) -
730 gui->mid_picon->get_w() / 2;
731 int x2 = x1 + gui->mid_picon->get_w();
732 if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
733 get_cursor_y() >= half_h && get_cursor_y() < h)
735 operation = DRAG_MAX_INPUT;
740 int x1 = (int)(plugin->config.output_max[subscript] * w / 0xffff) -
741 gui->mid_picon->get_w() / 2;
742 int x2 = x1 + gui->mid_picon->get_w();
743 if(get_cursor_x() >= x1 && get_cursor_x() < x2 &&
744 get_cursor_y() >= half_h && get_cursor_y() < h)
746 operation = DRAG_MAX_OUTPUT;
755 int HistogramSlider::button_release_event()
757 if(operation != NONE)
765 int HistogramSlider::cursor_motion_event()
767 //printf("HistogramSlider::cursor_motion_event 1\n");
768 if(operation != NONE)
770 float value = (float)get_cursor_x() * 0xffff / get_w();
771 CLAMP(value, 0, 0xffff);
772 int subscript = plugin->config.mode;
773 float input_min = plugin->config.input_min[subscript];
774 float input_max = plugin->config.input_max[subscript];
775 float input_mid = plugin->config.input_mid[subscript];
776 float input_mid_fraction = (input_mid - input_min) / (input_max - input_min);
781 input_min = MIN(input_max, value);
782 plugin->config.input_min[subscript] = (int)input_min;
783 input_mid = input_min + (input_max - input_min) * input_mid_fraction;
786 CLAMP(value, input_min, input_max);
787 input_mid = (int)value;
790 input_max = MAX(input_mid, value);
791 input_mid = input_min + (input_max - input_min) * input_mid_fraction;
793 case DRAG_MIN_OUTPUT:
794 value = MIN(plugin->config.output_max[subscript], value);
795 plugin->config.output_min[subscript] = (int)value;
797 case DRAG_MAX_OUTPUT:
798 value = MAX(plugin->config.output_min[subscript], value);
799 plugin->config.output_max[subscript] = (int)value;
803 if(operation == DRAG_MIN_INPUT ||
804 operation == DRAG_MID_INPUT ||
805 operation == DRAG_MAX_INPUT)
807 plugin->config.input_mid[subscript] = (int)input_mid;
808 plugin->config.input_min[subscript] = (int)input_min;
809 plugin->config.input_max[subscript] = (int)input_max;
814 gui->update_output();
817 gui->unlock_window();
818 plugin->send_configure_change();
819 //printf("HistogramSlider::cursor_motion_event 2\n");
821 //printf("HistogramSlider::cursor_motion_event 3\n");
827 void HistogramSlider::update()
831 int half_h = get_h() / 2;
832 int quarter_h = get_h() / 4;
833 int mode = plugin->config.mode;
837 int subscript = plugin->config.mode;
839 clear_box(0, 0, w, h);
846 case HISTOGRAM_GREEN:
854 for(int i = 0; i < w; i++)
856 int color = (int)(i * 0xff / w);
857 set_color(((r * color / 0xff) << 16) |
858 ((g * color / 0xff) << 8) |
863 draw_line(i, quarter_h, i, half_h);
864 color = (int)plugin->calculate_curve(i * 0xffff / w,
866 set_color(((r * color / 0xffff) << 16) |
867 ((g * color / 0xffff) << 8) |
868 (b * color / 0xffff));
869 draw_line(i, 0, i, quarter_h);
872 draw_line(i, 0, i, half_h);
881 draw_pixmap(gui->mid_picon,
882 (int)(plugin->config.input_mid[subscript] * w / 0xffff) -
883 gui->mid_picon->get_w() / 2,
885 min = plugin->config.input_min[subscript];
886 max = plugin->config.input_max[subscript];
890 min = plugin->config.output_min[subscript];
891 max = plugin->config.output_max[subscript];
894 draw_pixmap(gui->min_picon,
895 min * w / 0xffff - gui->min_picon->get_w() / 2,
897 draw_pixmap(gui->max_picon,
898 max * w / 0xffff - gui->max_picon->get_w() / 2,
901 // printf("HistogramSlider::update %d %d\n", min, max);
914 HistogramAuto::HistogramAuto(HistogramMain *plugin,
917 : BC_CheckBox(x, y, plugin->config.automatic, _("Automatic"))
919 this->plugin = plugin;
922 int HistogramAuto::handle_event()
924 plugin->config.automatic = get_value();
925 plugin->send_configure_change();
932 HistogramMode::HistogramMode(HistogramMain *plugin,
937 : BC_Radial(x, y, plugin->config.mode == value, text)
939 this->plugin = plugin;
942 int HistogramMode::handle_event()
944 plugin->config.mode = value;
945 plugin->thread->window->update_mode();
946 plugin->thread->window->input->update();
947 plugin->thread->window->output->update();
948 plugin->send_configure_change();
960 HistogramText::HistogramText(HistogramMain *plugin,
961 HistogramWindow *gui,
965 : BC_TumbleTextBox(gui,
973 this->plugin = plugin;
974 this->output = output;
978 int HistogramText::handle_event()
982 *output = atol(get_text());
984 plugin->thread->window->input->update();
985 plugin->thread->window->output->update();
986 plugin->send_configure_change();
1011 HistogramMain::HistogramMain(PluginServer *server)
1012 : PluginVClient(server)
1014 PLUGIN_CONSTRUCTOR_MACRO
1016 lookup[0] = lookup[1] = lookup[2] = lookup[3] = 0;
1017 accum[0] = accum[1] = accum[2] = accum[3] = accum[3] = 0;
1020 HistogramMain::~HistogramMain()
1022 PLUGIN_DESTRUCTOR_MACRO
1023 if(lookup[0]) delete [] lookup[0];
1024 if(lookup[1]) delete [] lookup[1];
1025 if(lookup[2]) delete [] lookup[2];
1026 if(lookup[3]) delete [] lookup[3];
1027 if(accum[0]) delete [] accum[0];
1028 if(accum[1]) delete [] accum[1];
1029 if(accum[2]) delete [] accum[2];
1030 if(accum[3]) delete [] accum[3];
1031 if(accum[4]) delete [] accum[4];
1032 if(engine) delete engine;
1035 char* HistogramMain::plugin_title() { return _("Histogram"); }
1036 int HistogramMain::is_realtime() { return 1; }
1039 NEW_PICON_MACRO(HistogramMain)
1041 SHOW_GUI_MACRO(HistogramMain, HistogramThread)
1043 SET_STRING_MACRO(HistogramMain)
1045 RAISE_WINDOW_MACRO(HistogramMain)
1047 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
1049 void HistogramMain::render_gui(void *data)
1054 //printf("HistogramMain::render_gui 1\n");
1055 thread->window->lock_window();
1056 //printf("HistogramMain::render_gui 2\n");
1057 calculate_histogram((VFrame*)data);
1058 //printf("HistogramMain::render_gui 3\n");
1059 if(config.automatic)
1061 calculate_automatic((VFrame*)data);
1063 //printf("HistogramMain::render_gui 3\n");
1065 thread->window->update_canvas();
1066 //printf("HistogramMain::render_gui 3\n");
1067 if(config.automatic)
1069 thread->window->update_input();
1071 //printf("HistogramMain::render_gui 3\n");
1072 thread->window->unlock_window();
1074 //printf("HistogramMain::render_gui 4\n");
1077 void HistogramMain::update_gui()
1081 thread->window->lock_window();
1082 int reconfigure = load_configuration();
1085 thread->window->update(0);
1086 if(!config.automatic)
1088 thread->window->update_input();
1091 thread->window->unlock_window();
1096 int HistogramMain::load_defaults()
1098 char directory[BCTEXTLEN], string[BCTEXTLEN];
1099 // set the default directory
1100 sprintf(directory, "%shistogram.rc", BCASTDIR);
1102 // load the defaults
1103 defaults = new Defaults(directory);
1106 for(int i = 0; i < 5; i++)
1108 sprintf(string, "INPUT_MIN_%d", i);
1109 config.input_min[i] = defaults->get(string, config.input_min[i]);
1110 sprintf(string, "INPUT_MID_%d", i);
1111 config.input_mid[i] = defaults->get(string, config.input_mid[i]);
1112 sprintf(string, "INPUT_MAX_%d", i);
1113 config.input_max[i] = defaults->get(string, config.input_max[i]);
1114 sprintf(string, "OUTPUT_MIN_%d", i);
1115 config.output_min[i] = defaults->get(string, config.output_min[i]);
1116 sprintf(string, "OUTPUT_MAX_%d", i);
1117 config.output_max[i] = defaults->get(string, config.output_max[i]);
1118 //printf("HistogramMain::load_defaults %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
1120 config.automatic = defaults->get("AUTOMATIC", config.automatic);
1121 config.mode = defaults->get("MODE", config.mode);
1122 config.threshold = defaults->get("THRESHOLD", config.threshold);
1127 int HistogramMain::save_defaults()
1129 char string[BCTEXTLEN];
1130 //printf("HistogramMain::save_defaults 1 %p\n", defaults);
1131 for(int i = 0; i < 5; i++)
1133 //printf("HistogramMain::save_defaults 1 %d\n", i);
1134 sprintf(string, "INPUT_MIN_%d", i);
1135 defaults->update(string, config.input_min[i]);
1136 //printf("HistogramMain::save_defaults 1 %d\n", i);
1137 sprintf(string, "INPUT_MID_%d", i);
1138 defaults->update(string, config.input_mid[i]);
1139 //printf("HistogramMain::save_defaults 1 %d\n", i);
1140 sprintf(string, "INPUT_MAX_%d", i);
1141 //printf("HistogramMain::save_defaults 1 %d\n", config.input_max[i]);
1142 defaults->update(string, config.input_max[i]);
1143 //printf("HistogramMain::save_defaults 1 %d\n", i);
1144 sprintf(string, "OUTPUT_MIN_%d", i);
1145 defaults->update(string, config.output_min[i]);
1146 //printf("HistogramMain::save_defaults 1 %d\n", i);
1147 sprintf(string, "OUTPUT_MAX_%d", i);
1148 defaults->update(string, config.output_max[i]);
1149 //printf("HistogramMain::save_defaults %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
1151 //printf("HistogramMain::save_defaults 3\n");
1152 defaults->update("AUTOMATIC", config.automatic);
1153 //printf("HistogramMain::save_defaults 4\n");
1154 defaults->update("MODE", config.mode);
1155 defaults->update("THRESHOLD", config.threshold);
1156 //printf("HistogramMain::save_defaults 5\n");
1158 //printf("HistogramMain::save_defaults 6\n");
1164 void HistogramMain::save_data(KeyFrame *keyframe)
1168 // cause data to be stored directly in text
1169 output.set_shared_string(keyframe->data, MESSAGESIZE);
1170 output.tag.set_title("HISTOGRAM");
1172 char string[BCTEXTLEN];
1173 for(int i = 0; i < 5; i++)
1175 sprintf(string, "INPUT_MIN_%d", i);
1176 output.tag.set_property(string, config.input_min[i]);
1177 sprintf(string, "INPUT_MID_%d", i);
1178 output.tag.set_property(string, config.input_mid[i]);
1179 sprintf(string, "INPUT_MAX_%d", i);
1180 output.tag.set_property(string, config.input_max[i]);
1181 sprintf(string, "OUTPUT_MIN_%d", i);
1182 output.tag.set_property(string, config.output_min[i]);
1183 sprintf(string, "OUTPUT_MAX_%d", i);
1184 output.tag.set_property(string, config.output_max[i]);
1185 //printf("HistogramMain::save_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
1187 output.tag.set_property("AUTOMATIC", config.automatic);
1188 output.tag.set_property("MODE", config.mode);
1189 output.tag.set_property("THRESHOLD", config.threshold);
1190 output.append_tag();
1191 output.terminate_string();
1194 void HistogramMain::read_data(KeyFrame *keyframe)
1198 input.set_shared_string(keyframe->data, strlen(keyframe->data));
1204 result = input.read_tag();
1208 if(input.tag.title_is("HISTOGRAM"))
1210 char string[BCTEXTLEN];
1211 for(int i = 0; i < 5; i++)
1213 sprintf(string, "INPUT_MIN_%d", i);
1214 config.input_min[i] = input.tag.get_property(string, config.input_min[i]);
1215 sprintf(string, "INPUT_MID_%d", i);
1216 config.input_mid[i] = input.tag.get_property(string, config.input_mid[i]);
1217 sprintf(string, "INPUT_MAX_%d", i);
1218 config.input_max[i] = input.tag.get_property(string, config.input_max[i]);
1219 sprintf(string, "OUTPUT_MIN_%d", i);
1220 config.output_min[i] = input.tag.get_property(string, config.output_min[i]);
1221 sprintf(string, "OUTPUT_MAX_%d", i);
1222 config.output_max[i] = input.tag.get_property(string, config.output_max[i]);
1223 //printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
1225 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
1226 config.mode = input.tag.get_property("MODE", config.mode);
1227 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
1233 float HistogramMain::calculate_curve(float input, int subscript)
1235 float y1, y2, y3, y4;
1236 float min = (float)config.input_min[subscript];
1237 float max = (float)config.input_max[subscript];
1238 float mid = (float)config.input_mid[subscript];
1239 float half = (float)HISTOGRAM_RANGE / 2;
1240 float output, output_perfect;
1241 float control = 1.0 / M_PI;
1242 float output_linear;
1245 if(input < min) return 0;
1248 if(input >= max) return HISTOGRAM_RANGE - 1;
1250 float slope1 = half / (mid - min);
1251 float slope2 = half / (max - mid);
1252 float min_slope = MIN(slope1, slope2);
1254 // value of 45` diagonal with midpoint
1255 output_perfect = half + min_slope * (input - mid);
1259 // Fraction of perfect diagonal to use
1260 float mid_fraction = (input - min) / (mid - min);
1261 // value of line connecting min to mid
1262 output_linear = mid_fraction * half;
1263 // Blend perfect diagonal with linear
1264 output = output_linear * (1.0 - mid_fraction) + output_perfect * mid_fraction;
1268 // Fraction of perfect diagonal to use
1269 float mid_fraction = (max - input) / (max - mid);
1270 // value of line connecting max to mid
1271 output_linear = half + (1.0 - mid_fraction) * half;
1272 // Blend perfect diagonal with linear
1273 output = output_linear * (1.0 - mid_fraction) + output_perfect * mid_fraction;
1282 // printf("HistogramMain::calculate_curve 1 %.0f %.0f %.0f %.0f %.0f\n",
1291 void HistogramMain::calculate_histogram(VFrame *data)
1293 if(!engine) engine = new HistogramEngine(this,
1294 get_project_smp() + 1,
1295 get_project_smp() + 1);
1299 for(int i = 0; i < 5; i++)
1300 accum[i] = new int64_t[HISTOGRAM_RANGE];
1303 engine->process_packages(HistogramEngine::HISTOGRAM, data);
1305 for(int i = 0; i < engine->get_total_clients(); i++)
1307 HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
1310 for(int j = 0; j < 5; j++)
1311 memcpy(accum[j], unit->accum[j], sizeof(int64_t) * HISTOGRAM_RANGE);
1315 for(int j = 0; j < 5; j++)
1317 int64_t *out = accum[j];
1318 int64_t *in = unit->accum[j];
1319 for(int k = 0; k < HISTOGRAM_RANGE; k++)
1325 // Remove top and bottom from calculations. Doesn't work in high
1326 // precision colormodels.
1327 for(int i = 0; i < 5; i++)
1330 accum[i][HISTOGRAM_RANGE - 1] = 0;
1335 void HistogramMain::calculate_automatic(VFrame *data)
1337 calculate_histogram(data);
1340 for(int i = 0; i < 3; i++)
1342 int64_t *accum = this->accum[i];
1345 for(int j = 0; j < HISTOGRAM_RANGE; j++)
1347 max = MAX(accum[j], max);
1350 int threshold = config.threshold * max / THRESHOLD_SCALE;
1354 config.input_min[i] = 0;
1355 for(int j = 0; j < HISTOGRAM_RANGE; j++)
1357 if(accum[j] > threshold)
1359 config.input_min[i] = j;
1366 config.input_max[i] = 0xffff;
1367 for(int j = HISTOGRAM_RANGE - 1; j >= 0; j--)
1369 if(accum[j] > threshold)
1371 config.input_max[i] = j;
1376 config.input_mid[i] = (config.input_min[i] + config.input_max[i]) / 2;
1385 int HistogramMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
1387 //printf("HistogramMain::process_realtime 1\n");
1388 TRON("HistogramMain::process_realtime");
1389 //printf("HistogramMain::process_realtime 1\n");
1390 int need_reconfigure = load_configuration();
1393 if(!engine) engine = new HistogramEngine(this,
1394 get_project_smp() + 1,
1395 get_project_smp() + 1);
1396 this->input = input_ptr;
1397 this->output = output_ptr;
1399 //printf("HistogramMain::process_realtime 1\n");
1400 send_render_gui(input_ptr);
1401 //printf("HistogramMain::process_realtime 1\n");
1403 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
1405 output_ptr->copy_from(input_ptr);
1407 //printf("HistogramMain::process_realtime 1\n");
1409 // Generate tables here. The same table is used by many packages to render
1410 // each horizontal stripe. Need to cover the entire output range in each
1411 // table to avoid green borders
1412 if(need_reconfigure || !lookup[0] || config.automatic)
1415 for(int i = 0; i < 4; i++)
1416 lookup[i] = new int[HISTOGRAM_RANGE];
1418 // Calculate new curves
1419 if(config.automatic)
1421 calculate_automatic(input);
1424 engine->process_packages(HistogramEngine::TABULATE, input);
1428 // Convert 16 bit lookup table to 8 bits
1429 switch(input->get_color_model())
1433 for(int i = 0; i < 0x100; i++)
1435 int subscript = (i << 8) | i;
1436 lookup[0][i] = lookup[0][subscript];
1437 lookup[1][i] = lookup[1][subscript];
1438 lookup[2][i] = lookup[2][subscript];
1439 lookup[3][i] = lookup[3][subscript];
1444 //printf("HistogramMain::process_realtime 1\n");
1450 engine->process_packages(HistogramEngine::APPLY, input);
1452 //printf("HistogramMain::process_realtime 100\n");
1455 TROFF("HistogramMain::process_realtime");
1465 HistogramPackage::HistogramPackage()
1473 HistogramUnit::HistogramUnit(HistogramEngine *server,
1474 HistogramMain *plugin)
1475 : LoadClient(server)
1477 this->plugin = plugin;
1478 this->server = server;
1479 bzero(accum, sizeof(accum));
1482 HistogramUnit::~HistogramUnit()
1484 if(accum[0]) delete [] accum[0];
1485 if(accum[1]) delete [] accum[1];
1486 if(accum[2]) delete [] accum[2];
1487 if(accum[3]) delete [] accum[3];
1488 if(accum[4]) delete [] accum[4];
1491 void HistogramUnit::process_package(LoadPackage *package)
1493 HistogramPackage *pkg = (HistogramPackage*)package;
1495 if(server->operation == HistogramEngine::HISTOGRAM)
1498 #define HISTOGRAM_HEAD(type) \
1500 for(int i = pkg->start; i < pkg->end; i++) \
1502 type *row = (type*)data->get_rows()[i]; \
1503 for(int j = 0; j < w; j++) \
1506 #define HISTOGRAM_TAIL(components) \
1512 if(components == 4) accum_a[row[3]]++; \
1514 row += components; \
1522 for(int i = 0; i < 5; i++)
1523 accum[i] = new int64_t[HISTOGRAM_RANGE];
1526 for(int i = 0; i < 5; i++)
1527 bzero(accum[i], sizeof(int64_t) * HISTOGRAM_RANGE);
1529 VFrame *data = server->data;
1530 int w = data->get_w();
1531 int h = data->get_h();
1532 int64_t *accum_r = accum[HISTOGRAM_RED];
1533 int64_t *accum_g = accum[HISTOGRAM_GREEN];
1534 int64_t *accum_b = accum[HISTOGRAM_BLUE];
1535 int64_t *accum_a = accum[HISTOGRAM_ALPHA];
1536 int64_t *accum_v = accum[HISTOGRAM_VALUE];
1537 int r, g, b, a, y, u, v;
1539 switch(data->get_color_model())
1542 HISTOGRAM_HEAD(unsigned char)
1543 r = (row[0] << 8) | row[0];
1544 g = (row[1] << 8) | row[1];
1545 b = (row[2] << 8) | row[2];
1549 HISTOGRAM_HEAD(unsigned char)
1550 y = (row[0] << 8) | row[0];
1551 u = (row[1] << 8) | row[1];
1552 v = (row[2] << 8) | row[2];
1553 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1557 HISTOGRAM_HEAD(unsigned char)
1558 r = (row[0] << 8) | row[0];
1559 g = (row[1] << 8) | row[1];
1560 b = (row[2] << 8) | row[2];
1564 HISTOGRAM_HEAD(unsigned char)
1565 y = (row[0] << 8) | row[0];
1566 u = (row[1] << 8) | row[1];
1567 v = (row[2] << 8) | row[2];
1568 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1572 HISTOGRAM_HEAD(uint16_t)
1579 HISTOGRAM_HEAD(uint16_t)
1583 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1586 case BC_RGBA16161616:
1587 HISTOGRAM_HEAD(uint16_t)
1593 case BC_YUVA16161616:
1594 HISTOGRAM_HEAD(uint16_t)
1598 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
1604 if(server->operation == HistogramEngine::APPLY)
1609 #define PROCESS(type, components) \
1611 for(int i = pkg->start; i < pkg->end; i++) \
1613 type *row = (type*)input->get_rows()[i]; \
1614 for(int j = 0; j < w; j++) \
1616 row[0] = lookup_r[row[0]]; \
1617 row[1] = lookup_g[row[1]]; \
1618 row[2] = lookup_b[row[2]]; \
1619 if(components == 4) row[3] = lookup_a[row[3]]; \
1620 row += components; \
1625 #define PROCESS_YUV(type, components, max) \
1627 for(int i = pkg->start; i < pkg->end; i++) \
1629 type *row = (type*)input->get_rows()[i]; \
1630 for(int j = 0; j < w; j++) \
1632 /* Convert to 16 bit RGB */ \
1635 y = (row[0] << 8) | row[0]; \
1636 u = (row[1] << 8) | row[1]; \
1637 v = (row[2] << 8) | row[2]; \
1638 if(components == 4) a = (row[3] << 8) | row[3]; \
1645 if(components == 4) a = row[3]; \
1648 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
1650 /* Look up in RGB domain */ \
1654 if(components == 4) a = lookup_a[a]; \
1656 /* Convert to 16 bit YUV */ \
1657 plugin->yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
1664 if(components == 4) row[3] = a >> 8; \
1671 if(components == 4) row[3] = a; \
1673 row += components; \
1681 VFrame *input = plugin->input;
1682 VFrame *output = plugin->output;
1683 int w = input->get_w();
1684 int h = input->get_h();
1685 int *lookup_r = plugin->lookup[0];
1686 int *lookup_g = plugin->lookup[1];
1687 int *lookup_b = plugin->lookup[2];
1688 int *lookup_a = plugin->lookup[3];
1689 int r, g, b, y, u, v, a;
1690 switch(input->get_color_model())
1693 PROCESS(unsigned char, 3)
1696 PROCESS(unsigned char, 4)
1699 PROCESS(uint16_t, 3)
1701 case BC_RGBA16161616:
1702 PROCESS(uint16_t, 4)
1705 PROCESS_YUV(unsigned char, 3, 0xff)
1708 PROCESS_YUV(unsigned char, 4, 0xff)
1711 PROCESS_YUV(uint16_t, 3, 0xffff)
1713 case BC_YUVA16161616:
1714 PROCESS_YUV(uint16_t, 4, 0xffff)
1718 if(server->operation == HistogramEngine::TABULATE)
1720 // Do conversion in 16 bit YUVA
1721 int min_output_r = plugin->config.output_min[0];
1722 int min_output_g = plugin->config.output_min[1];
1723 int min_output_b = plugin->config.output_min[2];
1724 int min_output_a = plugin->config.output_min[3];
1725 int min_output_v = plugin->config.output_min[4];
1726 int max_output_r = plugin->config.output_max[0];
1727 int max_output_g = plugin->config.output_max[1];
1728 int max_output_b = plugin->config.output_max[2];
1729 int max_output_a = plugin->config.output_max[3];
1730 int max_output_v = plugin->config.output_max[4];
1731 int colormodel = plugin->input->get_color_model();
1733 for(int i = pkg->start; i < pkg->end; i++)
1736 float r = plugin->calculate_curve((float)i, HISTOGRAM_RED);
1737 float g = plugin->calculate_curve((float)i, HISTOGRAM_GREEN);
1738 float b = plugin->calculate_curve((float)i, HISTOGRAM_BLUE);
1739 float a = plugin->calculate_curve((float)i, HISTOGRAM_ALPHA);
1742 r = plugin->calculate_curve((float)r, HISTOGRAM_VALUE);
1743 g = plugin->calculate_curve((float)g, HISTOGRAM_VALUE);
1744 b = plugin->calculate_curve((float)b, HISTOGRAM_VALUE);
1750 r = (float)min_output_r +
1752 (max_output_r - min_output_r) /
1753 (HISTOGRAM_RANGE - 1);
1756 (max_output_g - min_output_g) /
1757 (HISTOGRAM_RANGE - 1);
1760 (max_output_b - min_output_b) /
1761 (HISTOGRAM_RANGE - 1);
1764 (max_output_a - min_output_a) /
1765 (HISTOGRAM_RANGE - 1);
1767 //printf(" 1 %d -> ", r);
1770 (max_output_v - min_output_v) /
1771 (HISTOGRAM_RANGE - 1);
1772 //printf("%d\n", r);
1775 (max_output_v - min_output_v) /
1776 (HISTOGRAM_RANGE - 1);
1779 (max_output_v - min_output_v) /
1780 (HISTOGRAM_RANGE - 1);
1783 (max_output_v - min_output_v) /
1784 (HISTOGRAM_RANGE - 1);
1788 // Convert to desired colormodel
1793 plugin->lookup[0][i] = ((int)r) >> 8;
1794 plugin->lookup[1][i] = ((int)g) >> 8;
1795 plugin->lookup[2][i] = ((int)b) >> 8;
1796 plugin->lookup[3][i] = ((int)a) >> 8;
1799 // Can't look up yuv.
1800 plugin->lookup[0][i] = (int)r;
1801 plugin->lookup[1][i] = (int)g;
1802 plugin->lookup[2][i] = (int)b;
1803 plugin->lookup[3][i] = (int)a;
1815 HistogramEngine::HistogramEngine(HistogramMain *plugin,
1818 : LoadServer(total_clients, total_packages)
1820 this->plugin = plugin;
1823 void HistogramEngine::init_packages()
1830 total_size = data->get_h();
1833 total_size = HISTOGRAM_RANGE;
1836 total_size = data->get_h();
1839 int package_size = (int)((float)total_size /
1840 total_packages + 1);
1842 for(int i = 0; i < total_packages; i++)
1844 HistogramPackage *package = (HistogramPackage*)packages[i];
1845 package->start = start;
1846 package->end = start + package_size;
1847 if(package->end > total_size)
1848 package->end = total_size;
1849 start = package->end;
1853 LoadClient* HistogramEngine::new_client()
1855 return new HistogramUnit(this, plugin);
1858 LoadPackage* HistogramEngine::new_package()
1860 return new HistogramPackage;
1863 void HistogramEngine::process_packages(int operation, VFrame *data)
1866 this->operation = operation;
1867 LoadServer::process_packages();