00001 #include <math.h>
00002 #include <stdint.h>
00003 #include <string.h>
00004 #include <unistd.h>
00005
00006 #include "bcdisplayinfo.h"
00007 #include "bcsignals.h"
00008 #include "clip.h"
00009 #include "bchash.h"
00010 #include "filexml.h"
00011 #include "histogram.h"
00012 #include "histogramconfig.h"
00013 #include "histogramwindow.h"
00014 #include "keyframe.h"
00015 #include "language.h"
00016 #include "loadbalance.h"
00017 #include "playback3d.h"
00018 #include "plugincolors.h"
00019 #include "vframe.h"
00020 #include "workarounds.h"
00021
00022 #include "aggregated.h"
00023 #include "../colorbalance/aggregated.h"
00024 #include "../interpolate/aggregated.h"
00025 #include "../gamma/aggregated.h"
00026
00027 class HistogramMain;
00028 class HistogramEngine;
00029 class HistogramWindow;
00030
00031
00032
00033
00034
00035 REGISTER_PLUGIN(HistogramMain)
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 HistogramMain::HistogramMain(PluginServer *server)
00049 : PluginVClient(server)
00050 {
00051 PLUGIN_CONSTRUCTOR_MACRO
00052 engine = 0;
00053 for(int i = 0; i < HISTOGRAM_MODES; i++)
00054 {
00055 lookup[i] = 0;
00056 smoothed[i] = 0;
00057 linear[i] = 0;
00058 accum[i] = 0;
00059 preview_lookup[i] = 0;
00060 }
00061 current_point = -1;
00062 mode = HISTOGRAM_VALUE;
00063 dragging_point = 0;
00064 input = 0;
00065 output = 0;
00066 }
00067
00068 HistogramMain::~HistogramMain()
00069 {
00070 PLUGIN_DESTRUCTOR_MACRO
00071 for(int i = 0; i < HISTOGRAM_MODES;i++)
00072 {
00073 delete [] lookup[i];
00074 delete [] smoothed[i];
00075 delete [] linear[i];
00076 delete [] accum[i];
00077 delete [] preview_lookup[i];
00078 }
00079 delete engine;
00080 }
00081
00082 char* HistogramMain::plugin_title() { return N_("Histogram"); }
00083 int HistogramMain::is_realtime() { return 1; }
00084
00085
00086 #include "picon_png.h"
00087 NEW_PICON_MACRO(HistogramMain)
00088
00089 SHOW_GUI_MACRO(HistogramMain, HistogramThread)
00090
00091 SET_STRING_MACRO(HistogramMain)
00092
00093 RAISE_WINDOW_MACRO(HistogramMain)
00094
00095 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
00096
00097 void HistogramMain::render_gui(void *data)
00098 {
00099 if(thread)
00100 {
00101 SET_TRACE
00102
00103
00104 if(!config.automatic)
00105 {
00106
00107
00108 thread->window->lock_window("HistogramMain::render_gui 1");
00109 tabulate_curve(HISTOGRAM_RED, 0);
00110 tabulate_curve(HISTOGRAM_GREEN, 0);
00111 tabulate_curve(HISTOGRAM_BLUE, 0);
00112 thread->window->unlock_window();
00113 }
00114
00115 calculate_histogram((VFrame*)data, !config.automatic);
00116
00117 SET_TRACE
00118
00119 if(config.automatic)
00120 {
00121 SET_TRACE
00122 calculate_automatic((VFrame*)data);
00123
00124 SET_TRACE
00125
00126
00127 thread->window->lock_window("HistogramMain::render_gui 1");
00128 tabulate_curve(HISTOGRAM_RED, 0);
00129 tabulate_curve(HISTOGRAM_GREEN, 0);
00130 tabulate_curve(HISTOGRAM_BLUE, 0);
00131 thread->window->unlock_window();
00132
00133 SET_TRACE
00134
00135 calculate_histogram((VFrame*)data, 1);
00136 SET_TRACE
00137 }
00138
00139 SET_TRACE
00140 thread->window->lock_window("HistogramMain::render_gui 2");
00141 thread->window->update_canvas();
00142 if(config.automatic)
00143 {
00144 thread->window->update_input();
00145 }
00146 thread->window->unlock_window();
00147 SET_TRACE
00148 }
00149 }
00150
00151 void HistogramMain::update_gui()
00152 {
00153 if(thread)
00154 {
00155 thread->window->lock_window("HistogramMain::update_gui");
00156 int reconfigure = load_configuration();
00157 if(reconfigure)
00158 {
00159 thread->window->update(0);
00160 if(!config.automatic)
00161 {
00162 thread->window->update_input();
00163 }
00164 }
00165 thread->window->unlock_window();
00166 }
00167 }
00168
00169
00170 int HistogramMain::load_defaults()
00171 {
00172 char directory[BCTEXTLEN], string[BCTEXTLEN];
00173
00174 sprintf(directory, "%shistogram.rc", BCASTDIR);
00175
00176
00177 defaults = new BC_Hash(directory);
00178 defaults->load();
00179
00180 for(int j = 0; j < HISTOGRAM_MODES; j++)
00181 {
00182 while(config.points[j].last) delete config.points[j].last;
00183
00184 sprintf(string, "TOTAL_POINTS_%d", j);
00185 int total_points = defaults->get(string, 0);
00186
00187 for(int i = 0; i < total_points; i++)
00188 {
00189 HistogramPoint *point = new HistogramPoint;
00190 sprintf(string, "INPUT_X_%d_%d", j, i);
00191 point->x = defaults->get(string, point->x);
00192 sprintf(string, "INPUT_Y_%d_%d", j, i);
00193 point->y = defaults->get(string, point->y);
00194 config.points[j].append(point);
00195 }
00196 }
00197
00198
00199 for(int i = 0; i < HISTOGRAM_MODES; i++)
00200 {
00201 sprintf(string, "OUTPUT_MIN_%d", i);
00202 config.output_min[i] = defaults->get(string, config.output_min[i]);
00203 sprintf(string, "OUTPUT_MAX_%d", i);
00204 config.output_max[i] = defaults->get(string, config.output_max[i]);
00205 }
00206
00207 config.automatic = defaults->get("AUTOMATIC", config.automatic);
00208 mode = defaults->get("MODE", mode);
00209 CLAMP(mode, 0, HISTOGRAM_MODES - 1);
00210 config.threshold = defaults->get("THRESHOLD", config.threshold);
00211 config.plot = defaults->get("PLOT", config.plot);
00212 config.split = defaults->get("SPLIT", config.split);
00213 config.boundaries();
00214 return 0;
00215 }
00216
00217
00218 int HistogramMain::save_defaults()
00219 {
00220 char string[BCTEXTLEN];
00221
00222
00223
00224 for(int j = 0; j < HISTOGRAM_MODES; j++)
00225 {
00226 int total_points = config.points[j].total();
00227 sprintf(string, "TOTAL_POINTS_%d", j);
00228 defaults->update(string, total_points);
00229 HistogramPoint *current = config.points[j].first;
00230 int number = 0;
00231 while(current)
00232 {
00233 sprintf(string, "INPUT_X_%d_%d", j, number);
00234 defaults->update(string, current->x);
00235 sprintf(string, "INPUT_Y_%d_%d", j, number);
00236 defaults->update(string, current->y);
00237 current = NEXT;
00238 number++;
00239 }
00240 }
00241
00242
00243 for(int i = 0; i < HISTOGRAM_MODES; i++)
00244 {
00245 sprintf(string, "OUTPUT_MIN_%d", i);
00246 defaults->update(string, config.output_min[i]);
00247 sprintf(string, "OUTPUT_MAX_%d", i);
00248 defaults->update(string, config.output_max[i]);
00249 }
00250
00251 defaults->update("AUTOMATIC", config.automatic);
00252 defaults->update("MODE", mode);
00253 defaults->update("THRESHOLD", config.threshold);
00254 defaults->update("PLOT", config.plot);
00255 defaults->update("SPLIT", config.split);
00256 defaults->save();
00257 return 0;
00258 }
00259
00260
00261
00262 void HistogramMain::save_data(KeyFrame *keyframe)
00263 {
00264 FileXML output;
00265
00266
00267 output.set_shared_string(keyframe->data, MESSAGESIZE);
00268 output.tag.set_title("HISTOGRAM");
00269
00270 char string[BCTEXTLEN];
00271
00272
00273 for(int i = 0; i < HISTOGRAM_MODES; i++)
00274 {
00275 sprintf(string, "OUTPUT_MIN_%d", i);
00276 output.tag.set_property(string, config.output_min[i]);
00277 sprintf(string, "OUTPUT_MAX_%d", i);
00278 output.tag.set_property(string, config.output_max[i]);
00279
00280 }
00281
00282 output.tag.set_property("AUTOMATIC", config.automatic);
00283 output.tag.set_property("THRESHOLD", config.threshold);
00284 output.tag.set_property("PLOT", config.plot);
00285 output.tag.set_property("SPLIT", config.split);
00286 output.append_tag();
00287 output.tag.set_title("/HISTOGRAM");
00288 output.append_tag();
00289 output.append_newline();
00290
00291
00292
00293
00294
00295 for(int j = 0; j < HISTOGRAM_MODES; j++)
00296 {
00297 output.tag.set_title("POINTS");
00298 output.append_tag();
00299 output.append_newline();
00300
00301
00302 HistogramPoint *current = config.points[j].first;
00303 while(current)
00304 {
00305 output.tag.set_title("POINT");
00306 output.tag.set_property("X", current->x);
00307 output.tag.set_property("Y", current->y);
00308 output.append_tag();
00309 output.append_newline();
00310 current = NEXT;
00311 }
00312
00313
00314 output.tag.set_title("/POINTS");
00315 output.append_tag();
00316 output.append_newline();
00317 }
00318
00319
00320
00321
00322
00323
00324 output.terminate_string();
00325 }
00326
00327 void HistogramMain::read_data(KeyFrame *keyframe)
00328 {
00329 FileXML input;
00330
00331 input.set_shared_string(keyframe->data, strlen(keyframe->data));
00332
00333 int result = 0;
00334 int current_input_mode = 0;
00335
00336
00337 while(!result)
00338 {
00339 result = input.read_tag();
00340
00341 if(!result)
00342 {
00343 if(input.tag.title_is("HISTOGRAM"))
00344 {
00345 char string[BCTEXTLEN];
00346 for(int i = 0; i < HISTOGRAM_MODES; i++)
00347 {
00348 sprintf(string, "OUTPUT_MIN_%d", i);
00349 config.output_min[i] = input.tag.get_property(string, config.output_min[i]);
00350 sprintf(string, "OUTPUT_MAX_%d", i);
00351 config.output_max[i] = input.tag.get_property(string, config.output_max[i]);
00352
00353 }
00354 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
00355 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
00356 config.plot = input.tag.get_property("PLOT", config.plot);
00357 config.split = input.tag.get_property("SPLIT", config.split);
00358 }
00359 else
00360 if(input.tag.title_is("POINTS"))
00361 {
00362 if(current_input_mode < HISTOGRAM_MODES)
00363 {
00364 HistogramPoints *points = &config.points[current_input_mode];
00365 while(points->last)
00366 delete points->last;
00367 while(!result)
00368 {
00369 result = input.read_tag();
00370 if(!result)
00371 {
00372 if(input.tag.title_is("/POINTS"))
00373 {
00374 break;
00375 }
00376 else
00377 if(input.tag.title_is("POINT"))
00378 {
00379 points->insert(
00380 input.tag.get_property("X", 0.0),
00381 input.tag.get_property("Y", 0.0));
00382 }
00383 }
00384 }
00385
00386 }
00387 current_input_mode++;
00388 }
00389 }
00390 }
00391
00392 config.boundaries();
00393
00394 }
00395
00396 float HistogramMain::calculate_linear(float input,
00397 int subscript,
00398 int use_value)
00399 {
00400 int done = 0;
00401 float output;
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415 if(!done)
00416 {
00417
00418 float x1 = 0;
00419 float y1 = 0;
00420 float x2 = 1;
00421 float y2 = 1;
00422
00423
00424
00425
00426 HistogramPoints *points = &config.points[subscript];
00427 HistogramPoint *current = points->first;
00428 int done = 0;
00429 while(current && !done)
00430 {
00431 if(current->x > input)
00432 {
00433 x2 = current->x;
00434 y2 = current->y;
00435 done = 1;
00436 }
00437 else
00438 current = NEXT;
00439 }
00440
00441 current = points->last;
00442 done = 0;
00443 while(current && !done)
00444 {
00445 if(current->x <= input)
00446 {
00447 x1 = current->x;
00448 y1 = current->y;
00449 done = 1;
00450 }
00451 else
00452 current = PREVIOUS;
00453 }
00454
00455
00456
00457
00458
00459 if(!EQUIV(x2 - x1, 0))
00460 output = (input - x1) * (y2 - y1) / (x2 - x1) + y1;
00461 else
00462 output = input * y2;
00463
00464
00465
00466
00467
00468 }
00469
00470
00471 if(use_value)
00472 {
00473 output = calculate_linear(output, HISTOGRAM_VALUE, 0);
00474 }
00475
00476
00477 float output_min = config.output_min[subscript];
00478 float output_max = config.output_max[subscript];
00479 float output_left;
00480 float output_right;
00481 float output_linear;
00482
00483
00484 output = output_min +
00485 output *
00486 (output_max - output_min);
00487
00488
00489 return output;
00490 }
00491
00492 float HistogramMain::calculate_smooth(float input, int subscript)
00493 {
00494 float x_f = (input - MIN_INPUT) * HISTOGRAM_SLOTS / FLOAT_RANGE;
00495 int x_i1 = (int)x_f;
00496 int x_i2 = x_i1 + 1;
00497 CLAMP(x_i1, 0, HISTOGRAM_SLOTS - 1);
00498 CLAMP(x_i2, 0, HISTOGRAM_SLOTS - 1);
00499 CLAMP(x_f, 0, HISTOGRAM_SLOTS - 1);
00500
00501 float smooth1 = smoothed[subscript][x_i1];
00502 float smooth2 = smoothed[subscript][x_i2];
00503 float result = smooth1 + (smooth2 - smooth1) * (x_f - x_i1);
00504 CLAMP(result, 0, 1.0);
00505 return result;
00506 }
00507
00508
00509 void HistogramMain::calculate_histogram(VFrame *data, int do_value)
00510 {
00511
00512 if(!engine) engine = new HistogramEngine(this,
00513 get_project_smp() + 1,
00514 get_project_smp() + 1);
00515
00516 if(!accum[0])
00517 {
00518 for(int i = 0; i < HISTOGRAM_MODES; i++)
00519 accum[i] = new int[HISTOGRAM_SLOTS];
00520 }
00521
00522 engine->process_packages(HistogramEngine::HISTOGRAM, data, do_value);
00523
00524 for(int i = 0; i < engine->get_total_clients(); i++)
00525 {
00526 HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
00527
00528 if(i == 0)
00529 {
00530 for(int j = 0; j < HISTOGRAM_MODES; j++)
00531 {
00532 memcpy(accum[j], unit->accum[j], sizeof(int) * HISTOGRAM_SLOTS);
00533 }
00534 }
00535 else
00536 {
00537 for(int j = 0; j < HISTOGRAM_MODES; j++)
00538 {
00539 int *out = accum[j];
00540 int *in = unit->accum[j];
00541 for(int k = 0; k < HISTOGRAM_SLOTS; k++)
00542 out[k] += in[k];
00543 }
00544 }
00545 }
00546
00547
00548
00549 for(int i = 0; i < HISTOGRAM_MODES; i++)
00550 {
00551 accum[i][0] = 0;
00552 accum[i][HISTOGRAM_SLOTS - 1] = 0;
00553 }
00554 }
00555
00556
00557 void HistogramMain::calculate_automatic(VFrame *data)
00558 {
00559 calculate_histogram(data, 0);
00560 config.reset_points(1);
00561
00562
00563 for(int i = 0; i < 3; i++)
00564 {
00565 int *accum = this->accum[i];
00566 int pixels = data->get_w() * data->get_h();
00567 float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
00568 int threshold = (int)(white_fraction * pixels);
00569 int total = 0;
00570 float max_level = 1.0;
00571 float min_level = 0.0;
00572
00573
00574 for(int j = 0; j < HISTOGRAM_SLOTS; j++)
00575 {
00576 total += accum[j];
00577 if(total >= threshold)
00578 {
00579 max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
00580 break;
00581 }
00582 }
00583
00584
00585 total = 0;
00586 for(int j = HISTOGRAM_SLOTS - 1; j >= 0; j--)
00587 {
00588 total += accum[j];
00589 if(total >= threshold)
00590 {
00591 min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
00592 break;
00593 }
00594 }
00595
00596
00597 config.points[i].insert(max_level, 1.0);
00598 config.points[i].insert(min_level, 0.0);
00599 }
00600 }
00601
00602
00603
00604
00605
00606 int HistogramMain::calculate_use_opengl()
00607 {
00608
00609 int result = get_use_opengl() &&
00610 !config.automatic &&
00611 config.points[HISTOGRAM_RED].total() < 3 &&
00612 config.points[HISTOGRAM_GREEN].total() < 3 &&
00613 config.points[HISTOGRAM_BLUE].total() < 3 &&
00614 config.points[HISTOGRAM_VALUE].total() < 3 &&
00615 (!config.plot || !gui_open());
00616 return result;
00617 }
00618
00619
00620 int HistogramMain::process_buffer(VFrame *frame,
00621 int64_t start_position,
00622 double frame_rate)
00623 {
00624 SET_TRACE
00625 int need_reconfigure = load_configuration();
00626
00627
00628 SET_TRACE
00629 int use_opengl = calculate_use_opengl();
00630
00631
00632 read_frame(frame,
00633 0,
00634 start_position,
00635 frame_rate,
00636 use_opengl);
00637
00638
00639 if(use_opengl) return run_opengl();
00640
00641 if(!engine) engine = new HistogramEngine(this,
00642 get_project_smp() + 1,
00643 get_project_smp() + 1);
00644 this->input = frame;
00645 this->output = frame;
00646
00647
00648 if(config.plot || config.automatic) send_render_gui(frame);
00649
00650 SET_TRACE
00651
00652
00653
00654 if(need_reconfigure ||
00655 !lookup[0] ||
00656 !smoothed[0] ||
00657 !linear[0] ||
00658 config.automatic)
00659 {
00660 SET_TRACE
00661
00662 if(config.automatic)
00663 {
00664 calculate_automatic(input);
00665 }
00666 SET_TRACE
00667
00668
00669 for(int i = 0; i < 3; i++)
00670 tabulate_curve(i, 1);
00671 SET_TRACE
00672 }
00673
00674
00675
00676
00677 engine->process_packages(HistogramEngine::APPLY, input, 0);
00678
00679 SET_TRACE
00680
00681 return 0;
00682 }
00683
00684 void HistogramMain::tabulate_curve(int subscript, int use_value)
00685 {
00686 int i;
00687 if(!lookup[subscript])
00688 lookup[subscript] = new int[HISTOGRAM_SLOTS];
00689 if(!smoothed[subscript])
00690 smoothed[subscript] = new float[HISTOGRAM_SLOTS];
00691 if(!linear[subscript])
00692 linear[subscript] = new float[HISTOGRAM_SLOTS];
00693 if(!preview_lookup[subscript])
00694 preview_lookup[subscript] = new int[HISTOGRAM_SLOTS];
00695
00696
00697 float *current_smooth = smoothed[subscript];
00698 float *current_linear = linear[subscript];
00699
00700
00701 for(i = 0; i < HISTOGRAM_SLOTS; i++)
00702 {
00703 float input = (float)i / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
00704 current_linear[i] = calculate_linear(input, subscript, use_value);
00705 }
00706
00707
00708
00709
00710
00711
00712
00713 float prev = 0.0;
00714 for(i = 0; i < HISTOGRAM_SLOTS; i++)
00715 {
00716
00717
00718
00719
00720 current_smooth[i] = current_linear[i];
00721 }
00722
00723
00724 if(input)
00725 {
00726 switch(input->get_color_model())
00727 {
00728 case BC_RGB888:
00729 case BC_RGBA8888:
00730 for(i = 0; i < 0x100; i++)
00731 lookup[subscript][i] =
00732 (int)(calculate_smooth((float)i / 0xff, subscript) * 0xff);
00733 break;
00734
00735 default:
00736 for(i = 0; i < 0x10000; i++)
00737 lookup[subscript][i] =
00738 (int)(calculate_smooth((float)i / 0xffff, subscript) * 0xffff);
00739 break;
00740 }
00741 }
00742
00743
00744 if(!use_value)
00745 {
00746 for(i = 0; i < 0x10000; i++)
00747 preview_lookup[subscript][i] =
00748 (int)(calculate_smooth((float)i / 0xffff, subscript) * 0xffff);
00749 }
00750 }
00751
00752 int HistogramMain::handle_opengl()
00753 {
00754 #ifdef HAVE_GL
00755
00756 static char *histogram_get_pixel1 =
00757 "vec4 histogram_get_pixel()\n"
00758 "{\n"
00759 " return gl_FragColor;\n"
00760 "}\n";
00761
00762 static char *histogram_get_pixel2 =
00763 "uniform sampler2D tex;\n"
00764 "vec4 histogram_get_pixel()\n"
00765 "{\n"
00766 " return texture2D(tex, gl_TexCoord[0].st);\n"
00767 "}\n";
00768
00769 static char *head_frag =
00770 "// first input point\n"
00771 "uniform vec2 input_min_r;\n"
00772 "uniform vec2 input_min_g;\n"
00773 "uniform vec2 input_min_b;\n"
00774 "uniform vec2 input_min_v;\n"
00775 "// second input point\n"
00776 "uniform vec2 input_max_r;\n"
00777 "uniform vec2 input_max_g;\n"
00778 "uniform vec2 input_max_b;\n"
00779 "uniform vec2 input_max_v;\n"
00780 "// output points\n"
00781 "uniform vec4 output_min;\n"
00782 "uniform vec4 output_scale;\n"
00783 "void main()\n"
00784 "{\n";
00785
00786 static char *get_rgb_frag =
00787 " vec4 pixel = histogram_get_pixel();\n";
00788
00789 static char *get_yuv_frag =
00790 " vec4 pixel = histogram_get_pixel();\n"
00791 YUV_TO_RGB_FRAG("pixel");
00792
00793 #define APPLY_INPUT_CURVE(PIXEL, INPUT_MIN, INPUT_MAX) \
00794 "// apply input curve\n" \
00795 " if(" PIXEL " < 0.0)\n" \
00796 " " PIXEL " = 0.0;\n" \
00797 " else\n" \
00798 " if(" PIXEL " < " INPUT_MIN ".x)\n" \
00799 " " PIXEL " = " PIXEL " * " INPUT_MIN ".y / " INPUT_MIN ".x;\n" \
00800 " else\n" \
00801 " if(" PIXEL " < " INPUT_MAX ".x)\n" \
00802 " " PIXEL " = (" PIXEL " - " INPUT_MIN ".x) * \n" \
00803 " (" INPUT_MAX ".y - " INPUT_MIN ".y) / \n" \
00804 " (" INPUT_MAX ".x - " INPUT_MIN ".x) + \n" \
00805 " " INPUT_MIN ".y;\n" \
00806 " else\n" \
00807 " if(" PIXEL " < 1.0)\n" \
00808 " " PIXEL " = (" PIXEL " - " INPUT_MAX ".x) * \n" \
00809 " (1.0 - " INPUT_MAX ".y) / \n" \
00810 " (1.0 - " INPUT_MAX ".x) + \n" \
00811 " " INPUT_MAX ".y;\n" \
00812 " else\n" \
00813 " " PIXEL " = 1.0;\n"
00814
00815
00816
00817 static char *apply_histogram_frag =
00818 APPLY_INPUT_CURVE("pixel.r", "input_min_r", "input_max_r")
00819 APPLY_INPUT_CURVE("pixel.g", "input_min_g", "input_max_g")
00820 APPLY_INPUT_CURVE("pixel.b", "input_min_b", "input_max_b")
00821 "// apply output curve\n"
00822 " pixel.rgb *= output_scale.rgb;\n"
00823 " pixel.rgb += output_min.rgb;\n"
00824 APPLY_INPUT_CURVE("pixel.r", "input_min_v", "input_max_v")
00825 APPLY_INPUT_CURVE("pixel.g", "input_min_v", "input_max_v")
00826 APPLY_INPUT_CURVE("pixel.b", "input_min_v", "input_max_v")
00827 "// apply output curve\n"
00828 " pixel.rgb *= vec3(output_scale.a, output_scale.a, output_scale.a);\n"
00829 " pixel.rgb += vec3(output_min.a, output_min.a, output_min.a);\n";
00830
00831 static char *put_rgb_frag =
00832 " gl_FragColor = pixel;\n"
00833 "}\n";
00834
00835 static char *put_yuv_frag =
00836 RGB_TO_YUV_FRAG("pixel")
00837 " gl_FragColor = pixel;\n"
00838 "}\n";
00839
00840
00841
00842 get_output()->to_texture();
00843 get_output()->enable_opengl();
00844
00845 char *shader_stack[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
00846 int current_shader = 0;
00847 int aggregate_interpolation = 0;
00848 int aggregate_gamma = 0;
00849 int aggregate_colorbalance = 0;
00850
00851
00852 if(!strcmp(get_output()->get_prev_effect(2), "Interpolate Pixels") &&
00853 !strcmp(get_output()->get_prev_effect(1), "Gamma") &&
00854 !strcmp(get_output()->get_prev_effect(0), "Color Balance"))
00855 {
00856 aggregate_interpolation = 1;
00857 aggregate_gamma = 1;
00858 aggregate_colorbalance = 1;
00859 }
00860 else
00861 if(!strcmp(get_output()->get_prev_effect(1), "Gamma") &&
00862 !strcmp(get_output()->get_prev_effect(0), "Color Balance"))
00863 {
00864 aggregate_gamma = 1;
00865 aggregate_colorbalance = 1;
00866 }
00867 else
00868 if(!strcmp(get_output()->get_prev_effect(1), "Interpolate Pixels") &&
00869 !strcmp(get_output()->get_prev_effect(0), "Gamma"))
00870 {
00871 aggregate_interpolation = 1;
00872 aggregate_gamma = 1;
00873 }
00874 else
00875 if(!strcmp(get_output()->get_prev_effect(1), "Interpolate Pixels") &&
00876 !strcmp(get_output()->get_prev_effect(0), "Color Balance"))
00877 {
00878 aggregate_interpolation = 1;
00879 aggregate_colorbalance = 1;
00880 }
00881 else
00882 if(!strcmp(get_output()->get_prev_effect(0), "Interpolate Pixels"))
00883 aggregate_interpolation = 1;
00884 else
00885 if(!strcmp(get_output()->get_prev_effect(0), "Gamma"))
00886 aggregate_gamma = 1;
00887 else
00888 if(!strcmp(get_output()->get_prev_effect(0), "Color Balance"))
00889 aggregate_colorbalance = 1;
00890
00891
00892
00893 if(aggregate_interpolation)
00894 INTERPOLATE_COMPILE(shader_stack,
00895 current_shader)
00896
00897 if(aggregate_gamma)
00898 GAMMA_COMPILE(shader_stack,
00899 current_shader,
00900 aggregate_interpolation)
00901
00902 if(aggregate_colorbalance)
00903 COLORBALANCE_COMPILE(shader_stack,
00904 current_shader,
00905 aggregate_interpolation || aggregate_gamma)
00906
00907
00908 if(aggregate_interpolation || aggregate_gamma || aggregate_colorbalance)
00909 shader_stack[current_shader++] = histogram_get_pixel1;
00910 else
00911 shader_stack[current_shader++] = histogram_get_pixel2;
00912
00913 unsigned int shader = 0;
00914 switch(get_output()->get_color_model())
00915 {
00916 case BC_YUV888:
00917 case BC_YUVA8888:
00918 shader_stack[current_shader++] = head_frag;
00919 shader_stack[current_shader++] = get_yuv_frag;
00920 shader_stack[current_shader++] = apply_histogram_frag;
00921 shader_stack[current_shader++] = put_yuv_frag;
00922 break;
00923 default:
00924 shader_stack[current_shader++] = head_frag;
00925 shader_stack[current_shader++] = get_rgb_frag;
00926 shader_stack[current_shader++] = apply_histogram_frag;
00927 shader_stack[current_shader++] = put_rgb_frag;
00928 break;
00929 }
00930
00931 shader = VFrame::make_shader(0,
00932 shader_stack[0],
00933 shader_stack[1],
00934 shader_stack[2],
00935 shader_stack[3],
00936 shader_stack[4],
00937 shader_stack[5],
00938 shader_stack[6],
00939 shader_stack[7],
00940 shader_stack[8],
00941 shader_stack[9],
00942 shader_stack[10],
00943 shader_stack[11],
00944 shader_stack[12],
00945 shader_stack[13],
00946 shader_stack[14],
00947 shader_stack[15],
00948 0);
00949
00950 printf("HistogramMain::handle_opengl %d %d %d %d shader=%d\n",
00951 aggregate_interpolation,
00952 aggregate_gamma,
00953 aggregate_colorbalance,
00954 current_shader,
00955 shader);
00956
00957 float input_min_r[2] = { 0, 0 };
00958 float input_min_g[2] = { 0, 0 };
00959 float input_min_b[2] = { 0, 0 };
00960 float input_min_v[2] = { 0, 0 };
00961 float input_max_r[2] = { 1, 1 };
00962 float input_max_g[2] = { 1, 1 };
00963 float input_max_b[2] = { 1, 1 };
00964 float input_max_v[2] = { 1, 1 };
00965 float output_min[4] = { 0, 0, 0, 0 };
00966 float output_scale[4] = { 1, 1, 1, 1 };
00967
00968
00969 HistogramPoint *point1, *point2;
00970
00971 #define CONVERT_POINT(index, input_min, input_max) \
00972 point1 = config.points[index].first; \
00973 point2 = config.points[index].last; \
00974 if(point1) \
00975 { \
00976 input_min[0] = point1->x; \
00977 input_min[1] = point1->y; \
00978 if(point2 != point1) \
00979 { \
00980 input_max[0] = point2->x; \
00981 input_max[1] = point2->y; \
00982 } \
00983 }
00984
00985 CONVERT_POINT(HISTOGRAM_RED, input_min_r, input_max_r);
00986 CONVERT_POINT(HISTOGRAM_GREEN, input_min_g, input_max_g);
00987 CONVERT_POINT(HISTOGRAM_BLUE, input_min_b, input_max_b);
00988 CONVERT_POINT(HISTOGRAM_VALUE, input_min_v, input_max_v);
00989
00990
00991
00992
00993
00994
00995
00996 for(int i = 0; i < HISTOGRAM_MODES; i++)
00997 {
00998 output_min[i] = config.output_min[i];
00999 output_scale[i] = config.output_max[i] - config.output_min[i];
01000 }
01001
01002 if(shader > 0)
01003 {
01004 glUseProgram(shader);
01005 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
01006 if(aggregate_gamma) GAMMA_UNIFORMS(shader)
01007 if(aggregate_interpolation) INTERPOLATE_UNIFORMS(shader)
01008 if(aggregate_colorbalance) COLORBALANCE_UNIFORMS(shader)
01009 glUniform2fv(glGetUniformLocation(shader, "input_min_r"), 1, input_min_r);
01010 glUniform2fv(glGetUniformLocation(shader, "input_min_g"), 1, input_min_g);
01011 glUniform2fv(glGetUniformLocation(shader, "input_min_b"), 1, input_min_b);
01012 glUniform2fv(glGetUniformLocation(shader, "input_min_v"), 1, input_min_v);
01013 glUniform2fv(glGetUniformLocation(shader, "input_max_r"), 1, input_max_r);
01014 glUniform2fv(glGetUniformLocation(shader, "input_max_g"), 1, input_max_g);
01015 glUniform2fv(glGetUniformLocation(shader, "input_max_b"), 1, input_max_b);
01016 glUniform2fv(glGetUniformLocation(shader, "input_max_v"), 1, input_max_v);
01017 glUniform4fv(glGetUniformLocation(shader, "output_min"), 1, output_min);
01018 glUniform4fv(glGetUniformLocation(shader, "output_scale"), 1, output_scale);
01019 }
01020
01021 get_output()->init_screen();
01022 get_output()->bind_texture(0);
01023
01024 glDisable(GL_BLEND);
01025
01026
01027 if(config.split)
01028 {
01029 glBegin(GL_TRIANGLES);
01030 glNormal3f(0, 0, 1.0);
01031
01032 glTexCoord2f(0.0 / get_output()->get_texture_w(),
01033 0.0 / get_output()->get_texture_h());
01034 glVertex3f(0.0, -(float)get_output()->get_h(), 0);
01035
01036
01037 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
01038 (float)get_output()->get_h() / get_output()->get_texture_h());
01039 glVertex3f((float)get_output()->get_w(), -0.0, 0);
01040
01041 glTexCoord2f(0.0 / get_output()->get_texture_w(),
01042 (float)get_output()->get_h() / get_output()->get_texture_h());
01043 glVertex3f(0.0, -0.0, 0);
01044
01045
01046 glEnd();
01047 }
01048 else
01049 {
01050 get_output()->draw_texture();
01051 }
01052
01053 glUseProgram(0);
01054
01055
01056 if(config.split)
01057 {
01058 glBegin(GL_TRIANGLES);
01059 glNormal3f(0, 0, 1.0);
01060
01061
01062 glTexCoord2f(0.0 / get_output()->get_texture_w(),
01063 0.0 / get_output()->get_texture_h());
01064 glVertex3f(0.0, -(float)get_output()->get_h(), 0);
01065
01066 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
01067 0.0 / get_output()->get_texture_h());
01068 glVertex3f((float)get_output()->get_w(),
01069 -(float)get_output()->get_h(), 0);
01070
01071 glTexCoord2f((float)get_output()->get_w() / get_output()->get_texture_w(),
01072 (float)get_output()->get_h() / get_output()->get_texture_h());
01073 glVertex3f((float)get_output()->get_w(), -0.0, 0);
01074
01075
01076 glEnd();
01077 }
01078
01079 get_output()->set_opengl_state(VFrame::SCREEN);
01080 #endif
01081 }
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094 HistogramPackage::HistogramPackage()
01095 : LoadPackage()
01096 {
01097 }
01098
01099
01100
01101
01102 HistogramUnit::HistogramUnit(HistogramEngine *server,
01103 HistogramMain *plugin)
01104 : LoadClient(server)
01105 {
01106 this->plugin = plugin;
01107 this->server = server;
01108 for(int i = 0; i < HISTOGRAM_MODES; i++)
01109 accum[i] = new int[HISTOGRAM_SLOTS];
01110 }
01111
01112 HistogramUnit::~HistogramUnit()
01113 {
01114 for(int i = 0; i < HISTOGRAM_MODES; i++)
01115 delete [] accum[i];
01116 }
01117
01118 void HistogramUnit::process_package(LoadPackage *package)
01119 {
01120 HistogramPackage *pkg = (HistogramPackage*)package;
01121
01122 if(server->operation == HistogramEngine::HISTOGRAM)
01123 {
01124 int do_value = server->do_value;
01125
01126
01127 #define HISTOGRAM_HEAD(type) \
01128 { \
01129 for(int i = pkg->start; i < pkg->end; i++) \
01130 { \
01131 type *row = (type*)data->get_rows()[i]; \
01132 for(int j = 0; j < w; j++) \
01133 {
01134
01135 #define HISTOGRAM_TAIL(components) \
01136 \
01137 if(do_value) \
01138 { \
01139 CLAMP(r, 0, HISTOGRAM_SLOTS - 1); \
01140 CLAMP(g, 0, HISTOGRAM_SLOTS - 1); \
01141 CLAMP(b, 0, HISTOGRAM_SLOTS - 1); \
01142 r_out = lookup_r[r]; \
01143 g_out = lookup_g[g]; \
01144 b_out = lookup_b[b]; \
01145 \
01146 v = MAX(r_out, g_out); \
01147 v = MAX(v, b_out); \
01148 v += -HISTOGRAM_MIN * 0xffff / 100; \
01149 CLAMP(v, 0, HISTOGRAM_SLOTS - 1); \
01150 accum_v[v]++; \
01151 } \
01152 \
01153 r += -HISTOGRAM_MIN * 0xffff / 100; \
01154 g += -HISTOGRAM_MIN * 0xffff / 100; \
01155 b += -HISTOGRAM_MIN * 0xffff / 100; \
01156 CLAMP(r, 0, HISTOGRAM_SLOTS - 1); \
01157 CLAMP(g, 0, HISTOGRAM_SLOTS - 1); \
01158 CLAMP(b, 0, HISTOGRAM_SLOTS - 1); \
01159 accum_r[r]++; \
01160 accum_g[g]++; \
01161 accum_b[b]++; \
01162 row += components; \
01163 } \
01164 } \
01165 }
01166
01167
01168
01169
01170 VFrame *data = server->data;
01171 int w = data->get_w();
01172 int h = data->get_h();
01173 int *accum_r = accum[HISTOGRAM_RED];
01174 int *accum_g = accum[HISTOGRAM_GREEN];
01175 int *accum_b = accum[HISTOGRAM_BLUE];
01176 int *accum_v = accum[HISTOGRAM_VALUE];
01177 int32_t r, g, b, a, y, u, v;
01178 int r_out, g_out, b_out;
01179 int *lookup_r = plugin->preview_lookup[HISTOGRAM_RED];
01180 int *lookup_g = plugin->preview_lookup[HISTOGRAM_GREEN];
01181 int *lookup_b = plugin->preview_lookup[HISTOGRAM_BLUE];
01182
01183 switch(data->get_color_model())
01184 {
01185 case BC_RGB888:
01186 HISTOGRAM_HEAD(unsigned char)
01187 r = (row[0] << 8) | row[0];
01188 g = (row[1] << 8) | row[1];
01189 b = (row[2] << 8) | row[2];
01190 HISTOGRAM_TAIL(3)
01191 break;
01192 case BC_RGB_FLOAT:
01193 HISTOGRAM_HEAD(float)
01194 r = (int)(row[0] * 0xffff);
01195 g = (int)(row[1] * 0xffff);
01196 b = (int)(row[2] * 0xffff);
01197 HISTOGRAM_TAIL(3)
01198 break;
01199 case BC_YUV888:
01200 HISTOGRAM_HEAD(unsigned char)
01201 y = (row[0] << 8) | row[0];
01202 u = (row[1] << 8) | row[1];
01203 v = (row[2] << 8) | row[2];
01204 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
01205 HISTOGRAM_TAIL(3)
01206 break;
01207 case BC_RGBA8888:
01208 HISTOGRAM_HEAD(unsigned char)
01209 r = (row[0] << 8) | row[0];
01210 g = (row[1] << 8) | row[1];
01211 b = (row[2] << 8) | row[2];
01212 HISTOGRAM_TAIL(4)
01213 break;
01214 case BC_RGBA_FLOAT:
01215 HISTOGRAM_HEAD(float)
01216 r = (int)(row[0] * 0xffff);
01217 g = (int)(row[1] * 0xffff);
01218 b = (int)(row[2] * 0xffff);
01219 HISTOGRAM_TAIL(4)
01220 break;
01221 case BC_YUVA8888:
01222 HISTOGRAM_HEAD(unsigned char)
01223 y = (row[0] << 8) | row[0];
01224 u = (row[1] << 8) | row[1];
01225 v = (row[2] << 8) | row[2];
01226 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
01227 HISTOGRAM_TAIL(4)
01228 break;
01229 case BC_RGB161616:
01230 HISTOGRAM_HEAD(uint16_t)
01231 r = row[0];
01232 g = row[1];
01233 b = row[2];
01234 HISTOGRAM_TAIL(3)
01235 break;
01236 case BC_YUV161616:
01237 HISTOGRAM_HEAD(uint16_t)
01238 y = row[0];
01239 u = row[1];
01240 v = row[2];
01241 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
01242 HISTOGRAM_TAIL(3)
01243 break;
01244 case BC_RGBA16161616:
01245 HISTOGRAM_HEAD(uint16_t)
01246 r = row[0];
01247 g = row[1];
01248 b = row[2];
01249 HISTOGRAM_TAIL(3)
01250 break;
01251 case BC_YUVA16161616:
01252 HISTOGRAM_HEAD(uint16_t)
01253 y = row[0];
01254 u = row[1];
01255 v = row[2];
01256 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
01257 HISTOGRAM_TAIL(4)
01258 break;
01259 }
01260 }
01261 else
01262 if(server->operation == HistogramEngine::APPLY)
01263 {
01264
01265
01266
01267 #define PROCESS(type, components) \
01268 { \
01269 for(int i = pkg->start; i < pkg->end; i++) \
01270 { \
01271 type *row = (type*)input->get_rows()[i]; \
01272 for(int j = 0; j < w; j++) \
01273 { \
01274 if ( plugin->config.split && ((j + i * w / h) < w) ) \
01275 continue; \
01276 row[0] = lookup_r[row[0]]; \
01277 row[1] = lookup_g[row[1]]; \
01278 row[2] = lookup_b[row[2]]; \
01279 row += components; \
01280 } \
01281 } \
01282 }
01283
01284 #define PROCESS_YUV(type, components, max) \
01285 { \
01286 for(int i = pkg->start; i < pkg->end; i++) \
01287 { \
01288 type *row = (type*)input->get_rows()[i]; \
01289 for(int j = 0; j < w; j++) \
01290 { \
01291 if ( plugin->config.split && ((j + i * w / h) < w) ) \
01292 continue; \
01293 \
01294 if(max == 0xff) \
01295 { \
01296 y = (row[0] << 8) | row[0]; \
01297 u = (row[1] << 8) | row[1]; \
01298 v = (row[2] << 8) | row[2]; \
01299 } \
01300 else \
01301 { \
01302 y = row[0]; \
01303 u = row[1]; \
01304 v = row[2]; \
01305 } \
01306 \
01307 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
01308 \
01309 \
01310 r = lookup_r[r]; \
01311 g = lookup_g[g]; \
01312 b = lookup_b[b]; \
01313 \
01314 \
01315 plugin->yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
01316 \
01317 if(max == 0xff) \
01318 { \
01319 row[0] = y >> 8; \
01320 row[1] = u >> 8; \
01321 row[2] = v >> 8; \
01322 } \
01323 else \
01324 { \
01325 row[0] = y; \
01326 row[1] = u; \
01327 row[2] = v; \
01328 } \
01329 row += components; \
01330 } \
01331 } \
01332 }
01333
01334 #define PROCESS_FLOAT(components) \
01335 { \
01336 for(int i = pkg->start; i < pkg->end; i++) \
01337 { \
01338 float *row = (float*)input->get_rows()[i]; \
01339 for(int j = 0; j < w; j++) \
01340 { \
01341 if ( plugin->config.split && ((j + i * w / h) < w) ) \
01342 continue; \
01343 float r = row[0]; \
01344 float g = row[1]; \
01345 float b = row[2]; \
01346 \
01347 r = plugin->calculate_smooth(r, HISTOGRAM_RED); \
01348 g = plugin->calculate_smooth(g, HISTOGRAM_GREEN); \
01349 b = plugin->calculate_smooth(b, HISTOGRAM_BLUE); \
01350 \
01351 row[0] = r; \
01352 row[1] = g; \
01353 row[2] = b; \
01354 \
01355 row += components; \
01356 } \
01357 } \
01358 }
01359
01360
01361 VFrame *input = plugin->input;
01362 VFrame *output = plugin->output;
01363 int w = input->get_w();
01364 int h = input->get_h();
01365 int *lookup_r = plugin->lookup[0];
01366 int *lookup_g = plugin->lookup[1];
01367 int *lookup_b = plugin->lookup[2];
01368 int r, g, b, y, u, v, a;
01369 switch(input->get_color_model())
01370 {
01371 case BC_RGB888:
01372 PROCESS(unsigned char, 3)
01373 break;
01374 case BC_RGB_FLOAT:
01375 PROCESS_FLOAT(3);
01376 break;
01377 case BC_RGBA8888:
01378 PROCESS(unsigned char, 4)
01379 break;
01380 case BC_RGBA_FLOAT:
01381 PROCESS_FLOAT(4);
01382 break;
01383 case BC_RGB161616:
01384 PROCESS(uint16_t, 3)
01385 break;
01386 case BC_RGBA16161616:
01387 PROCESS(uint16_t, 4)
01388 break;
01389 case BC_YUV888:
01390 PROCESS_YUV(unsigned char, 3, 0xff)
01391 break;
01392 case BC_YUVA8888:
01393 PROCESS_YUV(unsigned char, 4, 0xff)
01394 break;
01395 case BC_YUV161616:
01396 PROCESS_YUV(uint16_t, 3, 0xffff)
01397 break;
01398 case BC_YUVA16161616:
01399 PROCESS_YUV(uint16_t, 4, 0xffff)
01400 break;
01401 }
01402 }
01403 }
01404
01405
01406
01407
01408
01409
01410 HistogramEngine::HistogramEngine(HistogramMain *plugin,
01411 int total_clients,
01412 int total_packages)
01413 : LoadServer(total_clients, total_packages)
01414 {
01415 this->plugin = plugin;
01416 }
01417
01418 void HistogramEngine::init_packages()
01419 {
01420 switch(operation)
01421 {
01422 case HISTOGRAM:
01423 total_size = data->get_h();
01424 break;
01425 case APPLY:
01426 total_size = data->get_h();
01427 break;
01428 }
01429
01430
01431 int package_size = (int)((float)total_size /
01432 get_total_packages() + 1);
01433 int start = 0;
01434
01435 for(int i = 0; i < get_total_packages(); i++)
01436 {
01437 HistogramPackage *package = (HistogramPackage*)get_package(i);
01438 package->start = total_size * i / get_total_packages();
01439 package->end = total_size * (i + 1) / get_total_packages();
01440 }
01441
01442
01443 for(int i = 0; i < get_total_clients(); i++)
01444 {
01445 HistogramUnit *unit = (HistogramUnit*)get_client(i);
01446 for(int i = 0; i < HISTOGRAM_MODES; i++)
01447 bzero(unit->accum[i], sizeof(int) * HISTOGRAM_SLOTS);
01448 }
01449
01450 }
01451
01452 LoadClient* HistogramEngine::new_client()
01453 {
01454 return new HistogramUnit(this, plugin);
01455 }
01456
01457 LoadPackage* HistogramEngine::new_package()
01458 {
01459 return new HistogramPackage;
01460 }
01461
01462 void HistogramEngine::process_packages(int operation, VFrame *data, int do_value)
01463 {
01464 this->data = data;
01465 this->operation = operation;
01466 this->do_value = do_value;
01467 LoadServer::process_packages();
01468 }
01469
01470
01471