4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "bcdisplayinfo.h"
28 #include "bcsignals.h"
32 #include "bistogram.h"
33 #include "bistogramconfig.h"
34 #include "bistogramwindow.h"
37 #include "loadbalance.h"
44 class HistogramEngine;
45 class HistogramWindow;
47 REGISTER_PLUGIN(HistogramMain)
49 HistogramMain::HistogramMain(PluginServer *server)
50 : PluginVClient(server)
54 for(int i = 0; i < HISTOGRAM_MODES; i++)
62 mode = HISTOGRAM_VALUE;
68 HistogramMain::~HistogramMain()
71 for(int i = 0; i < HISTOGRAM_MODES;i++)
74 delete [] smoothed[i];
81 const char* HistogramMain::plugin_title() { return _("Histogram Bezier"); }
82 int HistogramMain::is_realtime() { return 1; }
85 NEW_WINDOW_MACRO(HistogramMain, HistogramWindow)
86 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
88 void HistogramMain::render_gui(void *data)
92 calculate_histogram((VFrame*)data);
96 calculate_automatic((VFrame*)data);
99 HistogramWindow *window = (HistogramWindow *)thread->window;
100 window->lock_window("HistogramMain::render_gui");
101 window->update_canvas();
104 window->update_input();
106 window->unlock_window();
110 void HistogramMain::update_gui()
114 thread->window->lock_window("HistogramMain::update_gui");
115 int reconfigure = load_configuration();
118 HistogramWindow *window = (HistogramWindow *)thread->window;
120 if(!config.automatic)
122 window->update_input();
125 thread->window->unlock_window();
130 void HistogramMain::save_data(KeyFrame *keyframe)
134 // cause data to be stored directly in text
135 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
136 output.tag.set_title("HISTOGRAM");
138 char string[BCTEXTLEN];
141 for(int i = 0; i < HISTOGRAM_MODES; i++)
143 sprintf(string, "OUTPUT_MIN_%d", i);
144 output.tag.set_property(string, config.output_min[i]);
145 sprintf(string, "OUTPUT_MAX_%d", i);
146 output.tag.set_property(string, config.output_max[i]);
147 //printf("HistogramMain::save_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
150 output.tag.set_property("AUTOMATIC", config.automatic);
151 output.tag.set_property("THRESHOLD", config.threshold);
152 output.tag.set_property("SPLIT", config.split);
153 output.tag.set_property("INTERPOLATION", config.smoothMode);
155 output.tag.set_title("/HISTOGRAM");
157 output.append_newline();
163 for(int j = 0; j < HISTOGRAM_MODES; j++)
165 output.tag.set_title("POINTS");
167 output.append_newline();
170 HistogramPoint *current = config.points[j].first;
173 output.tag.set_title("POINT");
174 output.tag.set_property("X", current->x);
175 output.tag.set_property("Y", current->y);
176 output.tag.set_property("GRADIENT", current->gradient);
177 output.tag.set_property("XOFFSET_LEFT", current->xoffset_left);
178 output.tag.set_property("XOFFSET_RIGHT", current->xoffset_right);
180 output.tag.set_title("/POINT");
182 output.append_newline();
187 output.tag.set_title("/POINTS");
189 output.append_newline();
197 output.terminate_string();
200 void HistogramMain::read_data(KeyFrame *keyframe)
204 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
207 int current_input_mode = 0;
212 result = input.read_tag();
216 if(input.tag.title_is("HISTOGRAM"))
218 char string[BCTEXTLEN];
219 for(int i = 0; i < HISTOGRAM_MODES; i++)
221 sprintf(string, "OUTPUT_MIN_%d", i);
222 config.output_min[i] = input.tag.get_property(string, config.output_min[i]);
223 sprintf(string, "OUTPUT_MAX_%d", i);
224 config.output_max[i] = input.tag.get_property(string, config.output_max[i]);
225 //printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
227 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
228 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
229 config.split = input.tag.get_property("SPLIT", config.split);
230 config.smoothMode = input.tag.get_property("INTERPOLATION", config.smoothMode);
233 if(input.tag.title_is("POINTS"))
235 if(current_input_mode < HISTOGRAM_MODES)
237 HistogramPoints *points = &config.points[current_input_mode];
242 result = input.read_tag();
245 if(input.tag.title_is("/POINTS"))
250 if(input.tag.title_is("POINT"))
253 input.tag.get_property("X", 0.0),
254 input.tag.get_property("Y", 0.0));
255 points->last->gradient =
256 input.tag.get_property("GRADIENT", 1.0);
257 points->last->xoffset_left =
258 input.tag.get_property("XOFFSET_LEFT", -0.02);
259 points->last->xoffset_right =
260 input.tag.get_property("XOFFSET_RIGHT", 0.02);
266 current_input_mode++;
275 float HistogramMain::calculate_linear(float input,
294 float x1 = 0, y1 = 0;
297 float x2 = 1, y2 = 1;
301 // Get 2 points surrounding current position
302 HistogramPoints *points = &config.points[subscript];
303 HistogramPoint *current = points->first;
305 while(current && !done) {
306 if(current->x > input) {
309 grad2 = current->gradient;
310 x2left = current->xoffset_left;
317 current = points->last;
319 while(current && !done) {
320 if(current->x <= input) {
323 grad1 = current->gradient;
325 x1right = current->xoffset_right;
334 if(!EQUIV(x2 - x1, 0))
336 if (config.smoothMode == HISTOGRAM_LINEAR)
337 output = (input - x1) * (y2 - y1) / (x2 - x1) + y1;
338 else if (config.smoothMode == HISTOGRAM_POLYNOMINAL)
340 /* Construct third grade polynom between every two points */
343 float delx = input - x1;
344 output = (grad2 * dx + grad1 * dx - 2*dy) / (dx * dx * dx) * delx * delx * delx +
345 (dx * dx) * (3*dy - 2* grad1*dx - grad2*dx) / (dx * dx) * delx * delx + grad1*delx + y1;
347 else if (config.smoothMode == HISTOGRAM_BEZIER)
349 /* Using standart DeCasteljau algorithm */
350 float y1right = y1 + grad1 * x1right;
351 float y2left = y2 + grad2 * x2left;
353 float t = (input - x1) / (x2 - x1);
355 float pointAy = y1 + (y1right - y1) * t;
356 float pointBy = y1right + (y2left - y1right) * t;
357 float pointCy = y2left + (y2 - y2left) * t;
358 float pointABy = pointAy + (pointBy - pointAy) * t;
359 float pointBCy = pointBy + (pointCy - pointBy) * t;
360 output = pointABy + (pointBCy - pointABy) * t;
370 output = calculate_linear(output, HISTOGRAM_VALUE, 0);
374 float output_min = config.output_min[subscript];
375 float output_max = config.output_max[subscript];
377 // Compress output for value followed by channel
378 output = output_min + output * (output_max - output_min);
382 float HistogramMain::calculate_smooth(float input, int subscript)
384 float x_f = (input - HIST_MIN_INPUT) * HISTOGRAM_SLOTS / FLOAT_RANGE;
387 CLAMP(x_i1, 0, HISTOGRAM_SLOTS-1);
388 CLAMP(x_i2, 0, HISTOGRAM_SLOTS-1);
389 CLAMP(x_f, 0, HISTOGRAM_SLOTS-1);
391 float smooth1 = smoothed[subscript][x_i1];
392 float smooth2 = smoothed[subscript][x_i2];
393 float result = smooth1 + (smooth2 - smooth1) * (x_f - x_i1);
394 CLAMP(result, 0, 1.0);
399 void HistogramMain::calculate_histogram(VFrame *data)
402 if(!engine) engine = new HistogramEngine(this,
403 get_project_smp() + 1,
404 get_project_smp() + 1);
408 for(int i = 0; i < HISTOGRAM_MODES; i++)
409 accum[i] = new int[HISTOGRAM_SLOTS];
411 engine->process_packages(HistogramEngine::HISTOGRAM, data);
413 for(int i = 0; i < engine->get_total_clients(); i++) {
414 HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
416 for(int j = 0; j < HISTOGRAM_MODES; j++)
417 memcpy(accum[j], unit->accum[j], sizeof(int) * HISTOGRAM_SLOTS);
420 for(int j = 0; j < HISTOGRAM_MODES; j++) {
422 int *in = unit->accum[j];
423 for(int k = 0; k < HISTOGRAM_SLOTS; k++)
429 // Remove top and bottom from calculations. Doesn't work in high
430 // precision colormodels.
431 for(int i = 0; i < HISTOGRAM_MODES; i++) {
433 accum[i][HISTOGRAM_SLOTS - 1] = 0;
438 void HistogramMain::calculate_automatic(VFrame *data)
440 calculate_histogram(data);
441 config.reset_points();
444 for(int i = 0; i < 3; i++) {
445 int *accum = this->accum[i];
446 int pixels = data->get_w() * data->get_h();
447 float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
448 int threshold = (int)(white_fraction * pixels);
450 float max_level = 1.0;
451 float min_level = 0.0;
453 // Get histogram slot above threshold of pixels
454 for(int j = 0; j < HISTOGRAM_SLOTS; j++) {
456 if(total >= threshold) {
457 max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
462 // Get slot below 99% of pixels
464 for(int j = HISTOGRAM_SLOTS - 1; j >= 0; j--) {
466 if(total >= threshold) {
467 min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
471 config.points[i].insert(max_level, 1.0);
472 config.points[i].insert(min_level, 0.0);
476 int HistogramMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
479 int need_reconfigure = load_configuration();
482 if(!engine) engine = new HistogramEngine(this,
483 get_project_smp() + 1,
484 get_project_smp() + 1);
485 this->input = input_ptr;
486 this->output = output_ptr;
488 send_render_gui(input_ptr);
490 if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
492 output_ptr->copy_from(input_ptr);
496 // Generate tables here. The same table is used by many packages to render
497 // each horizontal stripe. Need to cover the entire output range in each
498 // table to avoid green borders
499 if( !lookup[0] || !smoothed[0] || !linear[0] || config.automatic)
500 need_reconfigure = 1;
501 if( need_reconfigure ) {
503 // Calculate new curves
504 if(config.automatic) {
505 calculate_automatic(input);
509 // Generate transfer tables for integer colormodels.
510 for(int i = 0; i < 3; i++)
511 tabulate_curve(i, 1);
516 engine->process_packages(HistogramEngine::APPLY, input);
522 void HistogramMain::tabulate_curve(int subscript, int use_value)
525 if(!lookup[subscript])
526 lookup[subscript] = new int[HISTOGRAM_SLOTS];
527 if(!smoothed[subscript])
528 smoothed[subscript] = new float[HISTOGRAM_SLOTS];
529 if(!linear[subscript])
530 linear[subscript] = new float[HISTOGRAM_SLOTS];
532 float *current_smooth = smoothed[subscript];
533 float *current_linear = linear[subscript];
536 for(i = 0; i < HISTOGRAM_SLOTS; i++) {
537 float input = (float)i / HISTOGRAM_SLOTS * FLOAT_RANGE + HIST_MIN_INPUT;
538 current_linear[i] = calculate_linear(input, subscript, use_value);
542 for(i = 0; i < HISTOGRAM_SLOTS; i++)
544 // current_smooth[i] = current_linear[i] * 0.001 +
546 current_smooth[i] = current_linear[i];
547 // prev = current_smooth[i];
549 // Generate lookup tables for integer colormodels
552 switch(input->get_color_model())
556 for(i = 0; i < 0x100; i++)
557 lookup[subscript][i] =
558 (int)(calculate_smooth((float)i / 0xff, subscript) * 0xff);
560 // All other integer colormodels are converted to 16 bit RGB
562 for(i = 0; i < 0x10000; i++)
563 lookup[subscript][i] =
564 (int)(calculate_smooth((float)i / 0xffff, subscript) * 0xffff);
570 HistogramPackage::HistogramPackage()
575 HistogramUnit::HistogramUnit(HistogramEngine *server,
576 HistogramMain *plugin)
579 this->plugin = plugin;
580 this->server = server;
581 for(int i = 0; i < HISTOGRAM_MODES; i++)
582 accum[i] = new int[HISTOGRAM_SLOTS];
585 HistogramUnit::~HistogramUnit()
587 for(int i = 0; i < HISTOGRAM_MODES; i++)
591 void HistogramUnit::process_package(LoadPackage *package)
593 HistogramPackage *pkg = (HistogramPackage*)package;
595 if(server->operation == HistogramEngine::HISTOGRAM)
598 #define HISTOGRAM_HEAD(type) \
600 for(int i = pkg->start; i < pkg->end; i++) \
602 type *row = (type*)data->get_rows()[i]; \
603 for(int j = 0; j < w; j++) \
606 #define HISTOGRAM_TAIL(components) \
607 /* v = (r * 76 + g * 150 + b * 29) >> 8; */ \
610 r += -HISTOGRAM_MIN * 0xffff / 100; \
611 g += -HISTOGRAM_MIN * 0xffff / 100; \
612 b += -HISTOGRAM_MIN * 0xffff / 100; \
613 v += -HISTOGRAM_MIN * 0xffff / 100; \
614 CLAMP(r, 0, HISTOGRAM_SLOTS-1); \
615 CLAMP(g, 0, HISTOGRAM_SLOTS-1); \
616 CLAMP(b, 0, HISTOGRAM_SLOTS-1); \
617 CLAMP(v, 0, HISTOGRAM_SLOTS-1); \
627 VFrame *data = server->data;
628 int w = data->get_w();
629 // int h = data->get_h();
630 int *accum_r = accum[HISTOGRAM_RED];
631 int *accum_g = accum[HISTOGRAM_GREEN];
632 int *accum_b = accum[HISTOGRAM_BLUE];
633 int *accum_v = accum[HISTOGRAM_VALUE];
634 int r, g, b, y, u, v;
636 switch(data->get_color_model())
639 HISTOGRAM_HEAD(unsigned char)
640 r = (row[0] << 8) | row[0];
641 g = (row[1] << 8) | row[1];
642 b = (row[2] << 8) | row[2];
646 HISTOGRAM_HEAD(float)
647 r = (int)(row[0] * 0xffff);
648 g = (int)(row[1] * 0xffff);
649 b = (int)(row[2] * 0xffff);
653 HISTOGRAM_HEAD(unsigned char)
654 y = (row[0] << 8) | row[0];
655 u = (row[1] << 8) | row[1];
656 v = (row[2] << 8) | row[2];
657 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
661 HISTOGRAM_HEAD(unsigned char)
662 r = (row[0] << 8) | row[0];
663 g = (row[1] << 8) | row[1];
664 b = (row[2] << 8) | row[2];
668 HISTOGRAM_HEAD(float)
669 r = (int)(row[0] * 0xffff);
670 g = (int)(row[1] * 0xffff);
671 b = (int)(row[2] * 0xffff);
675 HISTOGRAM_HEAD(unsigned char)
676 y = (row[0] << 8) | row[0];
677 u = (row[1] << 8) | row[1];
678 v = (row[2] << 8) | row[2];
679 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
683 HISTOGRAM_HEAD(uint16_t)
690 HISTOGRAM_HEAD(uint16_t)
694 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
697 case BC_RGBA16161616:
698 HISTOGRAM_HEAD(uint16_t)
704 case BC_YUVA16161616:
705 HISTOGRAM_HEAD(uint16_t)
709 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
715 if(server->operation == HistogramEngine::APPLY)
720 #define PROCESS(type, components) \
722 for(int i = pkg->start; i < pkg->end; i++) \
724 type *row = (type*)input->get_rows()[i]; \
725 for(int j = 0; j < w; j++) \
727 if ( plugin->config.split && ((j + i * w / h) < w) ) \
729 row[0] = lookup_r[row[0]]; \
730 row[1] = lookup_g[row[1]]; \
731 row[2] = lookup_b[row[2]]; \
737 #define PROCESS_YUV(type, components, max) \
739 for(int i = pkg->start; i < pkg->end; i++) \
741 type *row = (type*)input->get_rows()[i]; \
742 for(int j = 0; j < w; j++) \
744 if ( plugin->config.split && ((j + i * w / h) < w) ) \
746 /* Convert to 16 bit RGB */ \
749 y = (row[0] << 8) | row[0]; \
750 u = (row[1] << 8) | row[1]; \
751 v = (row[2] << 8) | row[2]; \
760 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
762 /* Look up in RGB domain */ \
767 /* Convert to 16 bit YUV */ \
768 plugin->yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
787 #define PROCESS_FLOAT(components) \
789 for(int i = pkg->start; i < pkg->end; i++) \
791 float *row = (float*)input->get_rows()[i]; \
792 for(int j = 0; j < w; j++) \
794 if ( plugin->config.split && ((j + i * w / h) < w) ) \
800 r = plugin->calculate_smooth(r, HISTOGRAM_RED); \
801 g = plugin->calculate_smooth(g, HISTOGRAM_GREEN); \
802 b = plugin->calculate_smooth(b, HISTOGRAM_BLUE); \
814 VFrame *input = plugin->input;
815 // VFrame *output = plugin->output;
816 int w = input->get_w(), h = input->get_h();
817 int *lookup_r = plugin->lookup[0];
818 int *lookup_g = plugin->lookup[1];
819 int *lookup_b = plugin->lookup[2];
820 int r, g, b, y, u, v;
821 switch(input->get_color_model())
824 PROCESS(unsigned char, 3)
830 PROCESS(unsigned char, 4)
838 case BC_RGBA16161616:
842 PROCESS_YUV(unsigned char, 3, 0xff)
845 PROCESS_YUV(unsigned char, 4, 0xff)
848 PROCESS_YUV(uint16_t, 3, 0xffff)
850 case BC_YUVA16161616:
851 PROCESS_YUV(uint16_t, 4, 0xffff)
862 HistogramEngine::HistogramEngine(HistogramMain *plugin,
865 : LoadServer(total_clients, total_packages)
867 this->plugin = plugin;
870 void HistogramEngine::init_packages()
874 total_size = data->get_h();
877 total_size = data->get_h();
881 for(int i = 0; i < get_total_packages(); i++) {
882 HistogramPackage *package = (HistogramPackage*)get_package(i);
883 package->start = total_size * i / get_total_packages();
884 package->end = total_size * (i + 1) / get_total_packages();
887 // Initialize clients here in case some don't get run.
888 for(int i = 0; i < get_total_clients(); i++) {
889 HistogramUnit *unit = (HistogramUnit*)get_client(i);
890 for(int i = 0; i < HISTOGRAM_MODES; i++)
891 bzero(unit->accum[i], sizeof(int) * HISTOGRAM_SLOTS);
896 LoadClient* HistogramEngine::new_client()
898 return new HistogramUnit(this, plugin);
901 LoadPackage* HistogramEngine::new_package()
903 return new HistogramPackage;
906 void HistogramEngine::process_packages(int operation, VFrame *data)
909 this->operation = operation;
910 LoadServer::process_packages();