00001 #include "bcdisplayinfo.h"
00002 #include "bcsignals.h"
00003 #include "chromakey.h"
00004 #include "clip.h"
00005 #include "bchash.h"
00006 #include "filexml.h"
00007 #include "guicast.h"
00008 #include "keyframe.h"
00009 #include "language.h"
00010 #include "loadbalance.h"
00011 #include "picon_png.h"
00012 #include "playback3d.h"
00013 #include "plugincolors.h"
00014 #include "pluginvclient.h"
00015 #include "vframe.h"
00016
00017 #include <stdint.h>
00018 #include <string.h>
00019 #include <unistd.h>
00020
00021
00022
00023 ChromaKeyConfig::ChromaKeyConfig ()
00024 {
00025 red = 0.0;
00026 green = 1.0;
00027 blue = 0.0;
00028
00029 min_brightness = 50.0;
00030 max_brightness = 100.0;
00031 tolerance = 15.0;
00032 saturation = 0.0;
00033 min_saturation = 50.0;
00034
00035 in_slope = 2;
00036 out_slope = 2;
00037 alpha_offset = 0;
00038
00039 spill_threshold = 0.0;
00040 spill_amount = 90.0;
00041
00042 show_mask = 0;
00043
00044 }
00045
00046
00047 void
00048 ChromaKeyConfig::copy_from (ChromaKeyConfig & src)
00049 {
00050 red = src.red;
00051 green = src.green;
00052 blue = src.blue;
00053 spill_threshold = src.spill_threshold;
00054 spill_amount = src.spill_amount;
00055 min_brightness = src.min_brightness;
00056 max_brightness = src.max_brightness;
00057 saturation = src.saturation;
00058 min_saturation = src.min_saturation;
00059 tolerance = src.tolerance;
00060 in_slope = src.in_slope;
00061 out_slope = src.out_slope;
00062 alpha_offset = src.alpha_offset;
00063 show_mask = src.show_mask;
00064 }
00065
00066 int
00067 ChromaKeyConfig::equivalent (ChromaKeyConfig & src)
00068 {
00069 return (EQUIV (red, src.red) &&
00070 EQUIV (green, src.green) &&
00071 EQUIV (blue, src.blue) &&
00072 EQUIV (spill_threshold, src.spill_threshold) &&
00073 EQUIV (spill_amount, src.spill_amount) &&
00074 EQUIV (min_brightness, src.min_brightness) &&
00075 EQUIV (max_brightness, src.max_brightness) &&
00076 EQUIV (saturation, src.saturation) &&
00077 EQUIV (min_saturation, src.min_saturation) &&
00078 EQUIV (tolerance, src.tolerance) &&
00079 EQUIV (in_slope, src.in_slope) &&
00080 EQUIV (out_slope, src.out_slope) &&
00081 EQUIV (show_mask, src.show_mask) &&
00082 EQUIV (alpha_offset, src.alpha_offset));
00083 }
00084
00085 void
00086 ChromaKeyConfig::interpolate (ChromaKeyConfig & prev,
00087 ChromaKeyConfig & next,
00088 int64_t prev_frame,
00089 int64_t next_frame, int64_t current_frame)
00090 {
00091 double next_scale =
00092 (double) (current_frame - prev_frame) / (next_frame - prev_frame);
00093 double prev_scale =
00094 (double) (next_frame - current_frame) / (next_frame - prev_frame);
00095
00096 this->red = prev.red * prev_scale + next.red * next_scale;
00097 this->green = prev.green * prev_scale + next.green * next_scale;
00098 this->blue = prev.blue * prev_scale + next.blue * next_scale;
00099 this->spill_threshold =
00100 prev.spill_threshold * prev_scale + next.spill_threshold * next_scale;
00101 this->spill_amount =
00102 prev.spill_amount * prev_scale + next.tolerance * next_scale;
00103 this->min_brightness =
00104 prev.min_brightness * prev_scale + next.min_brightness * next_scale;
00105 this->max_brightness =
00106 prev.max_brightness * prev_scale + next.max_brightness * next_scale;
00107 this->saturation =
00108 prev.saturation * prev_scale + next.saturation * next_scale;
00109 this->min_saturation =
00110 prev.min_saturation * prev_scale + next.min_saturation * next_scale;
00111 this->tolerance = prev.tolerance * prev_scale + next.tolerance * next_scale;
00112 this->in_slope = prev.in_slope * prev_scale + next.in_slope * next_scale;
00113 this->out_slope = prev.out_slope * prev_scale + next.out_slope * next_scale;
00114 this->alpha_offset =
00115 prev.alpha_offset * prev_scale + next.alpha_offset * next_scale;
00116 this->show_mask = next.show_mask;
00117
00118 }
00119
00120 int
00121 ChromaKeyConfig::get_color ()
00122 {
00123 int red = (int) (CLIP (this->red, 0, 1) * 0xff);
00124 int green = (int) (CLIP (this->green, 0, 1) * 0xff);
00125 int blue = (int) (CLIP (this->blue, 0, 1) * 0xff);
00126 return (red << 16) | (green << 8) | blue;
00127 }
00128
00129
00130
00131 ChromaKeyWindow::ChromaKeyWindow (ChromaKeyHSV * plugin, int x, int y):BC_Window (plugin->gui_string,
00132 x,
00133 y,
00134 400,
00135 450,
00136 400,
00137 450,
00138 0,
00139 0,
00140 1)
00141 {
00142 this->plugin = plugin;
00143 color_thread = 0;
00144 }
00145
00146 ChromaKeyWindow::~ChromaKeyWindow ()
00147 {
00148 delete color_thread;
00149 }
00150
00151 void
00152 ChromaKeyWindow::create_objects ()
00153 {
00154 int y = 10, y1, x1 = 0, x2 = 10;
00155 int x = 30;
00156
00157 BC_Title *title;
00158 BC_Bar *bar;
00159 int ymargin = get_text_height(MEDIUMFONT) + 5;
00160 int ymargin2 = get_text_height(MEDIUMFONT) + 10;
00161
00162 add_subwindow (title = new BC_Title (x2, y, _("Color:")));
00163
00164 add_subwindow (color = new ChromaKeyColor (plugin, this, x, y + 25));
00165
00166 add_subwindow (sample =
00167 new BC_SubWindow (x + color->get_w () + 10, y, 100, 50));
00168 y += sample->get_h () + 10;
00169
00170 add_subwindow (use_colorpicker =
00171 new ChromaKeyUseColorPicker (plugin, this, x, y));
00172 y += use_colorpicker->get_h() + 10;
00173 add_subwindow (show_mask = new ChromaKeyShowMask (plugin, x2, y));
00174 y += show_mask->get_h() + 5;
00175
00176 add_subwindow(bar = new BC_Bar(x2, y, get_w() - x2 * 2));
00177 y += bar->get_h() + 5;
00178 y1 = y;
00179 add_subwindow (new BC_Title (x2, y, _("Key parameters:")));
00180 y += ymargin;
00181 add_subwindow (title = new BC_Title (x, y, _("Hue Tolerance:")));
00182 if(title->get_w() > x1) x1 = title->get_w();
00183 y += ymargin;
00184 add_subwindow (title = new BC_Title (x, y, _("Min. Brightness:")));
00185 if(title->get_w() > x1) x1 = title->get_w();
00186 y += ymargin;
00187 add_subwindow (title = new BC_Title (x, y, _("Max. Brightness:")));
00188 if(title->get_w() > x1) x1 = title->get_w();
00189 y += ymargin;
00190 add_subwindow (title = new BC_Title (x, y, _("Saturation Offset:")));
00191 if(title->get_w() > x1) x1 = title->get_w();
00192 y += ymargin;
00193 add_subwindow (title = new BC_Title (x, y, _("Min Saturation:")));
00194 if(title->get_w() > x1) x1 = title->get_w();
00195 y += ymargin2;
00196
00197 add_subwindow(bar = new BC_Bar(x2, y, get_w() - x2 * 2));
00198 y += bar->get_h() + 5;
00199 add_subwindow (title = new BC_Title (x2, y, _("Mask tweaking:")));
00200 y += ymargin;
00201 add_subwindow (title = new BC_Title (x, y, _("In Slope:")));
00202 if(title->get_w() > x1) x1 = title->get_w();
00203 y += ymargin;
00204 add_subwindow (title = new BC_Title (x, y, _("Out Slope:")));
00205 if(title->get_w() > x1) x1 = title->get_w();
00206 y += ymargin;
00207 add_subwindow (title = new BC_Title (x, y, _("Alpha Offset:")));
00208 if(title->get_w() > x1) x1 = title->get_w();
00209 y += ymargin2;
00210
00211
00212
00213 add_subwindow(bar = new BC_Bar(x2, y, get_w() - x2 * 2));
00214 y += bar->get_h() + 5;
00215 add_subwindow (title = new BC_Title (x2, y, _("Spill light control:")));
00216 y += ymargin;
00217 add_subwindow (title = new BC_Title (x, y, _("Spill Threshold:")));
00218 if(title->get_w() > x1) x1 = title->get_w();
00219 y += ymargin;
00220 add_subwindow (title = new BC_Title (x, y, _("Spill Compensation:")));
00221 if(title->get_w() > x1) x1 = title->get_w();
00222 y += ymargin;
00223
00224
00225 y = y1;
00226 y += ymargin;
00227 x1 += x;
00228
00229
00230
00231 add_subwindow (tolerance = new ChromaKeyTolerance (plugin, x1, y));
00232 y += ymargin;
00233 add_subwindow (min_brightness = new ChromaKeyMinBrightness (plugin, x1, y));
00234 y += ymargin;
00235 add_subwindow (max_brightness = new ChromaKeyMaxBrightness (plugin, x1, y));
00236 y += ymargin;
00237 add_subwindow (saturation = new ChromaKeySaturation (plugin, x1, y));
00238 y += ymargin;
00239 add_subwindow (min_saturation = new ChromaKeyMinSaturation (plugin, x1, y));
00240 y += ymargin;
00241
00242 y += bar->get_h() + 5;
00243 y += ymargin2;
00244 add_subwindow (in_slope = new ChromaKeyInSlope (plugin, x1, y));
00245 y += ymargin;
00246 add_subwindow (out_slope = new ChromaKeyOutSlope (plugin, x1, y));
00247 y += ymargin;
00248 add_subwindow (alpha_offset = new ChromaKeyAlphaOffset (plugin, x1, y));
00249 y += ymargin;
00250
00251 y += bar->get_h() + 5;
00252 y += ymargin2;
00253 add_subwindow (spill_threshold = new ChromaKeySpillThreshold (plugin, x1, y));
00254 y += ymargin;
00255 add_subwindow (spill_amount = new ChromaKeySpillAmount (plugin, x1, y));
00256
00257 color_thread = new ChromaKeyColorThread (plugin, this);
00258
00259 update_sample ();
00260 show_window ();
00261 flush ();
00262 }
00263
00264 void
00265 ChromaKeyWindow::update_sample ()
00266 {
00267 sample->set_color (plugin->config.get_color ());
00268 sample->draw_box (0, 0, sample->get_w (), sample->get_h ());
00269 sample->set_color (BLACK);
00270 sample->draw_rectangle (0, 0, sample->get_w (), sample->get_h ());
00271 sample->flash ();
00272 }
00273
00274
00275
00276 WINDOW_CLOSE_EVENT (ChromaKeyWindow)
00277 ChromaKeyColor::ChromaKeyColor (ChromaKeyHSV * plugin,
00278 ChromaKeyWindow * gui, int x, int y):
00279 BC_GenericButton (x, y, _("Color..."))
00280 {
00281 this->plugin = plugin;
00282 this->gui = gui;
00283 }
00284
00285 int
00286 ChromaKeyColor::handle_event ()
00287 {
00288 gui->color_thread->start_window (plugin->config.get_color (), 0xff);
00289 return 1;
00290 }
00291
00292
00293
00294
00295 ChromaKeyMinBrightness::ChromaKeyMinBrightness (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
00296 y,
00297 0,
00298 200, 200, (float) 0, (float) 100, plugin->config.min_brightness)
00299 {
00300 this->plugin = plugin;
00301 set_precision (0.01);
00302 }
00303
00304 int
00305 ChromaKeyMinBrightness::handle_event ()
00306 {
00307 plugin->config.min_brightness = get_value ();
00308 plugin->send_configure_change ();
00309 return 1;
00310 }
00311
00312 ChromaKeyMaxBrightness::ChromaKeyMaxBrightness (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
00313 y,
00314 0,
00315 200, 200, (float) 0, (float) 100, plugin->config.max_brightness)
00316 {
00317 this->plugin = plugin;
00318 set_precision (0.01);
00319 }
00320
00321 int
00322 ChromaKeyMaxBrightness::handle_event ()
00323 {
00324 plugin->config.max_brightness = get_value ();
00325 plugin->send_configure_change ();
00326 return 1;
00327 }
00328
00329
00330 ChromaKeySaturation::ChromaKeySaturation (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
00331 y,
00332 0, 200, 200, (float) 0, (float) 100, plugin->config.saturation)
00333 {
00334 this->plugin = plugin;
00335 set_precision (0.01);
00336 }
00337
00338 int
00339 ChromaKeySaturation::handle_event ()
00340 {
00341 plugin->config.saturation = get_value ();
00342 plugin->send_configure_change ();
00343 return 1;
00344 }
00345
00346 ChromaKeyMinSaturation::ChromaKeyMinSaturation (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
00347 y,
00348 0,
00349 200, 200, (float) 0, (float) 100, plugin->config.min_saturation)
00350 {
00351 this->plugin = plugin;
00352 set_precision (0.01);
00353 }
00354
00355 int
00356 ChromaKeyMinSaturation::handle_event ()
00357 {
00358 plugin->config.min_saturation = get_value ();
00359 plugin->send_configure_change ();
00360 return 1;
00361 }
00362
00363
00364 ChromaKeyTolerance::ChromaKeyTolerance (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
00365 y,
00366 0, 200, 200, (float) 0, (float) 100, plugin->config.tolerance)
00367 {
00368 this->plugin = plugin;
00369 set_precision (0.01);
00370 }
00371
00372 int
00373 ChromaKeyTolerance::handle_event ()
00374 {
00375 plugin->config.tolerance = get_value ();
00376 plugin->send_configure_change ();
00377 return 1;
00378 }
00379
00380
00381
00382 ChromaKeyInSlope::ChromaKeyInSlope (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
00383 y,
00384 0, 200, 200, (float) 0, (float) 20, plugin->config.in_slope)
00385 {
00386 this->plugin = plugin;
00387 set_precision (0.01);
00388 }
00389
00390 int
00391 ChromaKeyInSlope::handle_event ()
00392 {
00393 plugin->config.in_slope = get_value ();
00394 plugin->send_configure_change ();
00395 return 1;
00396 }
00397
00398
00399 ChromaKeyOutSlope::ChromaKeyOutSlope (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
00400 y,
00401 0, 200, 200, (float) 0, (float) 20, plugin->config.out_slope)
00402 {
00403 this->plugin = plugin;
00404 set_precision (0.01);
00405 }
00406
00407 int
00408 ChromaKeyOutSlope::handle_event ()
00409 {
00410 plugin->config.out_slope = get_value ();
00411 plugin->send_configure_change ();
00412 return 1;
00413 }
00414
00415
00416 ChromaKeyAlphaOffset::ChromaKeyAlphaOffset (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
00417 y,
00418 0,
00419 200, 200, (float) -100, (float) 100, plugin->config.alpha_offset)
00420 {
00421 this->plugin = plugin;
00422 set_precision (0.01);
00423 }
00424
00425 int
00426 ChromaKeyAlphaOffset::handle_event ()
00427 {
00428 plugin->config.alpha_offset = get_value ();
00429 plugin->send_configure_change ();
00430 return 1;
00431 }
00432
00433 ChromaKeyShowMask::ChromaKeyShowMask (ChromaKeyHSV * plugin, int x, int y):BC_CheckBox (x, y, plugin->config.show_mask,
00434 _
00435 ("Show Mask"))
00436 {
00437 this->plugin = plugin;
00438
00439 }
00440
00441 int
00442 ChromaKeyShowMask::handle_event ()
00443 {
00444 plugin->config.show_mask = get_value ();
00445 plugin->send_configure_change ();
00446 return 1;
00447 }
00448
00449 ChromaKeyUseColorPicker::ChromaKeyUseColorPicker (ChromaKeyHSV * plugin, ChromaKeyWindow * gui, int x, int y):BC_GenericButton (x, y,
00450 _
00451 ("Use color picker"))
00452 {
00453 this->plugin = plugin;
00454 this->gui = gui;
00455 }
00456
00457 int
00458 ChromaKeyUseColorPicker::handle_event ()
00459 {
00460 plugin->config.red = plugin->get_red ();
00461 plugin->config.green = plugin->get_green ();
00462 plugin->config.blue = plugin->get_blue ();
00463 gui->update_sample ();
00464 plugin->send_configure_change ();
00465 return 1;
00466 }
00467
00468
00469
00470 ChromaKeySpillThreshold::ChromaKeySpillThreshold (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
00471 y,
00472 0,
00473 200, 200, (float) 0, (float) 100, plugin->config.spill_threshold)
00474 {
00475 this->plugin = plugin;
00476 set_precision (0.01);
00477 }
00478
00479 int
00480 ChromaKeySpillThreshold::handle_event ()
00481 {
00482 plugin->config.spill_threshold = get_value ();
00483 plugin->send_configure_change ();
00484 return 1;
00485 }
00486
00487 ChromaKeySpillAmount::ChromaKeySpillAmount (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
00488 y,
00489 0, 200, 200, (float) 0, (float) 100, plugin->config.spill_amount)
00490 {
00491 this->plugin = plugin;
00492 set_precision (0.01);
00493 }
00494
00495 int
00496 ChromaKeySpillAmount::handle_event ()
00497 {
00498 plugin->config.spill_amount = get_value ();
00499 plugin->send_configure_change ();
00500 return 1;
00501 }
00502
00503
00504
00505
00506
00507
00508 ChromaKeyColorThread::ChromaKeyColorThread (ChromaKeyHSV * plugin, ChromaKeyWindow * gui):ColorThread (1,
00509 _
00510 ("Inner color"))
00511 {
00512 this->plugin = plugin;
00513 this->gui = gui;
00514 }
00515
00516 int
00517 ChromaKeyColorThread::handle_new_color (int output, int alpha)
00518 {
00519 plugin->config.red = (float) (output & 0xff0000) / 0xff0000;
00520 plugin->config.green = (float) (output & 0xff00) / 0xff00;
00521 plugin->config.blue = (float) (output & 0xff) / 0xff;
00522 gui->update_sample ();
00523 plugin->send_configure_change ();
00524 return 1;
00525 }
00526
00527
00528
00529
00530
00531
00532
00533
00534 PLUGIN_THREAD_OBJECT (ChromaKeyHSV, ChromaKeyThread, ChromaKeyWindow) ChromaKeyServer::ChromaKeyServer (ChromaKeyHSV * plugin):LoadServer (plugin->PluginClient::smp + 1,
00535 plugin->PluginClient::smp +
00536 1)
00537 {
00538 this->plugin = plugin;
00539 }
00540
00541 void
00542 ChromaKeyServer::init_packages ()
00543 {
00544 for (int i = 0; i < get_total_packages (); i++)
00545 {
00546 ChromaKeyPackage *pkg = (ChromaKeyPackage *) get_package (i);
00547 pkg->y1 = plugin->input->get_h () * i / get_total_packages ();
00548 pkg->y2 = plugin->input->get_h () * (i + 1) / get_total_packages ();
00549 }
00550
00551 }
00552 LoadClient *
00553 ChromaKeyServer::new_client ()
00554 {
00555 return new ChromaKeyUnit (plugin, this);
00556 }
00557
00558 LoadPackage *
00559 ChromaKeyServer::new_package ()
00560 {
00561 return new ChromaKeyPackage;
00562 }
00563
00564
00565
00566 ChromaKeyPackage::ChromaKeyPackage ():LoadPackage ()
00567 {
00568 }
00569
00570 ChromaKeyUnit::ChromaKeyUnit (ChromaKeyHSV * plugin, ChromaKeyServer * server):LoadClient
00571 (server)
00572 {
00573 this->plugin = plugin;
00574 }
00575
00576
00577
00578
00579 #define ABS(a) ((a<0)?-(a):a)
00580
00581 #define OUTER_VARIABLES \
00582 float red = plugin->config.red; \
00583 float green = plugin->config.green; \
00584 float blue = plugin->config.blue; \
00585 \
00586 float in_slope = plugin->config.in_slope / 100; \
00587 float out_slope = plugin->config.out_slope / 100; \
00588 \
00589 float tolerance = plugin->config.tolerance / 100; \
00590 float tolerance_in = tolerance - in_slope; \
00591 float tolerance_out = tolerance + out_slope; \
00592 \
00593 float sat = plugin->config.saturation / 100; \
00594 float min_s = plugin->config.min_saturation / 100; \
00595 float min_s_in = min_s + in_slope; \
00596 float min_s_out = min_s - out_slope; \
00597 \
00598 float min_v = plugin->config.min_brightness / 100; \
00599 float min_v_in = min_v + in_slope; \
00600 float min_v_out = min_v - out_slope; \
00601 \
00602 float max_v = plugin->config.max_brightness / 100; \
00603 float max_v_in = max_v - in_slope; \
00604 float max_v_out = max_v + out_slope; \
00605 \
00606 float spill_threshold = plugin->config.spill_threshold / 100; \
00607 float spill_amount = 1.0 - plugin->config.spill_amount / 100; \
00608 \
00609 float alpha_offset = plugin->config.alpha_offset / 100; \
00610 \
00611 \
00612 float hue_key, saturation_key, value_key; \
00613 HSV::rgb_to_hsv(red, \
00614 green, \
00615 blue, \
00616 hue_key, \
00617 saturation_key, \
00618 value_key);
00619
00620
00621 template <typename component_type>
00622 void ChromaKeyUnit::process_chromakey(int components,
00623 component_type max,
00624 bool use_yuv,
00625 ChromaKeyPackage *pkg)
00626 {
00627 OUTER_VARIABLES
00628
00629 int w = plugin->input->get_w();
00630
00631 for (int i = pkg->y1; i < pkg->y2; i++)
00632 {
00633 component_type *row = (component_type *) plugin->input->get_rows ()[i];
00634
00635 for (int j = 0; j < w; j++)
00636 {
00637 float a = 1;
00638
00639 float r = (float) row[0] / max;
00640 float g = (float) row[1] / max;
00641 float b = (float) row[2] / max;
00642
00643 float h, s, v;
00644
00645 float av = 1, ah = 1, as = 1, avm = 1;
00646 bool has_match = true;
00647
00648 if (use_yuv)
00649 {
00650
00651 float y = r;
00652 float u = g;
00653 float v = b;
00654 YUV::yuv_to_rgb_f (r, g, b, y, u - 0.5, v - 0.5);
00655 }
00656
00657 HSV::rgb_to_hsv (r, g, b, h, s, v);
00658
00659
00660 if (tolerance == 0)
00661 ah = 1.0;
00662 else
00663 if (ABS (h - hue_key) < tolerance_in * 180)
00664 ah = 0;
00665 else
00666 if ((out_slope != 0) && (ABS (h - hue_key) < tolerance * 180))
00667
00668 ah = ABS (h - hue_key) / tolerance / 360;
00669 else
00670 if (ABS (h - hue_key) < tolerance_out * 180)
00671
00672 ah = ABS (h - hue_key) / tolerance_out / 360;
00673 else
00674 has_match = false;
00675
00676
00677 if (has_match)
00678 {
00679 if (min_s == 0)
00680 as = 0;
00681 else if (s - sat >= min_s_in)
00682 as = 0;
00683 else if ((out_slope != 0) && (s - sat > min_s))
00684 as = (s - sat - min_s) / (min_s * 2);
00685 else if (s - sat > min_s_out)
00686 as = (s - sat - min_s_out) / (min_s_out * 2);
00687 else
00688 has_match = false;
00689 }
00690
00691
00692 if (has_match)
00693 {
00694 if (min_v == 0)
00695 av = 0;
00696 else if (v >= min_v_in)
00697 av = 0;
00698 else if ((out_slope != 0) && (v > min_v))
00699 av = (v - min_v) / (min_v * 2);
00700 else if (v > min_v_out)
00701 av = (v - min_v_out) / (min_v_out * 2);
00702 else
00703 has_match = false;
00704 }
00705
00706
00707 if (has_match)
00708 {
00709 if (max_v == 0)
00710 avm = 1;
00711 else if (v <= max_v_in)
00712 avm = 0;
00713 else if ((out_slope != 0) && (v < max_v))
00714 avm = (v - max_v) / (max_v * 2);
00715 else if (v < max_v_out)
00716 avm = (v - max_v_out) / (max_v_out * 2);
00717 else
00718 has_match = false;
00719 }
00720
00721
00722 if (has_match)
00723 a = MAX (MAX (ah, av), MAX (as, avm));
00724
00725
00726 if ((ABS (h - hue_key) < spill_threshold * 180) ||
00727 ((ABS (h - hue_key) > 360)
00728 && (ABS (h - hue_key) - 360 < spill_threshold * 180)))
00729 {
00730 s = s * spill_amount * ABS (h - hue_key) / (spill_threshold * 180);
00731
00732 HSV::hsv_to_rgb (r, g, b, h, s, v);
00733
00734 if (use_yuv)
00735 {
00736 float y;
00737 float u;
00738 float v;
00739 YUV::rgb_to_yuv_f (r, g, b, y, u, v);
00740 CLAMP (y, 0, 1.0);
00741 CLAMP (u, 0, 1.0);
00742 CLAMP (v, 0, 1.0);
00743 row[0] = (component_type) ((float) y * max);
00744 row[1] = (component_type) ((float) (u + 0.5) * max);
00745 row[2] = (component_type) ((float) (v + 0.5) * max);
00746 }
00747 else
00748 {
00749 CLAMP (r, 0, 1.0);
00750 CLAMP (g, 0, 1.0);
00751 CLAMP (b, 0, 1.0);
00752 row[0] = (component_type) ((float) r * max);
00753 row[1] = (component_type) ((float) g * max);
00754 row[2] = (component_type) ((float) b * max);
00755 }
00756 }
00757
00758 a += alpha_offset;
00759 CLAMP (a, 0.0, 1.0);
00760
00761 if (plugin->config.show_mask)
00762 {
00763
00764 if (use_yuv)
00765 {
00766 row[0] = (component_type) ((float) a * max);
00767 row[1] = (component_type) ((float) max / 2);
00768 row[2] = (component_type) ((float) max / 2);
00769 }
00770 else
00771 {
00772 row[0] = (component_type) ((float) a * max);
00773 row[1] = (component_type) ((float) a * max);
00774 row[2] = (component_type) ((float) a * max);
00775 }
00776 }
00777
00778
00779 if (components == 4)
00780 {
00781 row[3] = MIN ((component_type) (a * max), row[3]);
00782 }
00783 else if (use_yuv)
00784 {
00785 row[0] = (component_type) ((float) a * row[0]);
00786 row[1] =
00787 (component_type) ((float) a * (row[1] - (max / 2 + 1)) +
00788 max / 2 + 1);
00789 row[2] =
00790 (component_type) ((float) a * (row[2] - (max / 2 + 1)) +
00791 max / 2 + 1);
00792 }
00793 else
00794 {
00795 row[0] = (component_type) ((float) a * row[0]);
00796 row[1] = (component_type) ((float) a * row[1]);
00797 row[2] = (component_type) ((float) a * row[2]);
00798 }
00799
00800 row += components;
00801 }
00802 }
00803 }
00804
00805
00806
00807
00808 void ChromaKeyUnit::process_package(LoadPackage *package)
00809 {
00810 ChromaKeyPackage *pkg = (ChromaKeyPackage*)package;
00811
00812
00813 switch(plugin->input->get_color_model())
00814 {
00815 case BC_RGB_FLOAT:
00816 process_chromakey<float> (3, 1.0, 0, pkg);
00817 break;
00818 case BC_RGBA_FLOAT:
00819 process_chromakey<float> ( 4, 1.0, 0, pkg);
00820 break;
00821 case BC_RGB888:
00822 process_chromakey<unsigned char> ( 3, 0xff, 0, pkg);
00823 break;
00824 case BC_RGBA8888:
00825 process_chromakey<unsigned char> ( 4, 0xff, 0, pkg);
00826 break;
00827 case BC_YUV888:
00828 process_chromakey<unsigned char> ( 3, 0xff, 1, pkg);
00829 break;
00830 case BC_YUVA8888:
00831 process_chromakey<unsigned char> ( 4, 0xff, 1, pkg);
00832 break;
00833 case BC_YUV161616:
00834 process_chromakey<uint16_t> (3, 0xffff, 1, pkg);
00835 break;
00836 case BC_YUVA16161616:
00837 process_chromakey<uint16_t> (4, 0xffff, 1, pkg);
00838 break;
00839 }
00840
00841 }
00842
00843
00844
00845
00846
00847 REGISTER_PLUGIN(ChromaKeyHSV)
00848
00849
00850
00851 ChromaKeyHSV::ChromaKeyHSV(PluginServer *server)
00852 : PluginVClient(server)
00853 {
00854 PLUGIN_CONSTRUCTOR_MACRO
00855 engine = 0;
00856 }
00857
00858 ChromaKeyHSV::~ChromaKeyHSV()
00859 {
00860 PLUGIN_DESTRUCTOR_MACRO
00861 if(engine) delete engine;
00862 }
00863
00864
00865 int ChromaKeyHSV::process_buffer(VFrame *frame,
00866 int64_t start_position,
00867 double frame_rate)
00868 {
00869 load_configuration();
00870 this->input = frame;
00871 this->output = frame;
00872
00873
00874 read_frame(frame,
00875 0,
00876 start_position,
00877 frame_rate,
00878 get_use_opengl());
00879 if(get_use_opengl()) return run_opengl();
00880
00881
00882 if(!engine) engine = new ChromaKeyServer(this);
00883 engine->process_packages();
00884
00885 return 0;
00886 }
00887
00888 char* ChromaKeyHSV::plugin_title() { return N_("Chroma key (HSV)"); }
00889 int ChromaKeyHSV::is_realtime() { return 1; }
00890
00891 NEW_PICON_MACRO(ChromaKeyHSV)
00892
00893 LOAD_CONFIGURATION_MACRO(ChromaKeyHSV, ChromaKeyConfig)
00894
00895 int ChromaKeyHSV::load_defaults ()
00896 {
00897 char directory[BCTEXTLEN];
00898
00899 sprintf (directory, "%schromakey-hsv.rc", BCASTDIR);
00900
00901
00902 defaults = new BC_Hash (directory);
00903 defaults->load ();
00904
00905 config.red = defaults->get ("RED", config.red);
00906 config.green = defaults->get ("GREEN", config.green);
00907 config.blue = defaults->get ("BLUE", config.blue);
00908 config.min_brightness =
00909 defaults->get ("MIN_BRIGHTNESS", config.min_brightness);
00910 config.max_brightness =
00911 defaults->get ("MAX_BRIGHTNESS", config.max_brightness);
00912 config.saturation = defaults->get ("SATURATION", config.saturation);
00913 config.min_saturation =
00914 defaults->get ("MIN_SATURATION", config.min_saturation);
00915 config.tolerance = defaults->get ("TOLERANCE", config.tolerance);
00916 config.spill_threshold =
00917 defaults->get ("SPILL_THRESHOLD", config.spill_threshold);
00918 config.spill_amount = defaults->get ("SPILL_AMOUNT", config.spill_amount);
00919 config.in_slope = defaults->get ("IN_SLOPE", config.in_slope);
00920 config.out_slope = defaults->get ("OUT_SLOPE", config.out_slope);
00921 config.alpha_offset = defaults->get ("ALPHA_OFFSET", config.alpha_offset);
00922 config.show_mask = defaults->get ("SHOW_MASK", config.show_mask);
00923 return 0;
00924 }
00925
00926 int
00927 ChromaKeyHSV::save_defaults ()
00928 {
00929 defaults->update ("RED", config.red);
00930 defaults->update ("GREEN", config.green);
00931 defaults->update ("BLUE", config.blue);
00932 defaults->update ("MIN_BRIGHTNESS", config.min_brightness);
00933 defaults->update ("MAX_BRIGHTNESS", config.max_brightness);
00934 defaults->update ("SATURATION", config.saturation);
00935 defaults->update ("MIN_SATURATION", config.min_saturation);
00936 defaults->update ("TOLERANCE", config.tolerance);
00937 defaults->update ("IN_SLOPE", config.in_slope);
00938 defaults->update ("OUT_SLOPE", config.out_slope);
00939 defaults->update ("ALPHA_OFFSET", config.alpha_offset);
00940 defaults->update ("SPILL_THRESHOLD", config.spill_threshold);
00941 defaults->update ("SPILL_AMOUNT", config.spill_amount);
00942 defaults->update ("SHOW_MASK", config.show_mask);
00943 defaults->save ();
00944 return 0;
00945 }
00946
00947 void
00948 ChromaKeyHSV::save_data (KeyFrame * keyframe)
00949 {
00950 FileXML output;
00951 output.set_shared_string (keyframe->data, MESSAGESIZE);
00952 output.tag.set_title ("CHROMAKEY_HSV");
00953 output.tag.set_property ("RED", config.red);
00954 output.tag.set_property ("GREEN", config.green);
00955 output.tag.set_property ("BLUE", config.blue);
00956 output.tag.set_property ("MIN_BRIGHTNESS", config.min_brightness);
00957 output.tag.set_property ("MAX_BRIGHTNESS", config.max_brightness);
00958 output.tag.set_property ("SATURATION", config.saturation);
00959 output.tag.set_property ("MIN_SATURATION", config.min_saturation);
00960 output.tag.set_property ("TOLERANCE", config.tolerance);
00961 output.tag.set_property ("IN_SLOPE", config.in_slope);
00962 output.tag.set_property ("OUT_SLOPE", config.out_slope);
00963 output.tag.set_property ("ALPHA_OFFSET", config.alpha_offset);
00964 output.tag.set_property ("SPILL_THRESHOLD", config.spill_threshold);
00965 output.tag.set_property ("SPILL_AMOUNT", config.spill_amount);
00966 output.tag.set_property ("SHOW_MASK", config.show_mask);
00967 output.append_tag ();
00968 output.tag.set_title ("/CHROMAKEY_HSV");
00969 output.append_tag ();
00970 output.terminate_string ();
00971 }
00972
00973 void
00974 ChromaKeyHSV::read_data (KeyFrame * keyframe)
00975 {
00976 FileXML input;
00977
00978 input.set_shared_string (keyframe->data, strlen (keyframe->data));
00979
00980 while (!input.read_tag ())
00981 {
00982 if (input.tag.title_is ("CHROMAKEY_HSV"))
00983 {
00984 config.red = input.tag.get_property ("RED", config.red);
00985 config.green = input.tag.get_property ("GREEN", config.green);
00986 config.blue = input.tag.get_property ("BLUE", config.blue);
00987 config.min_brightness =
00988 input.tag.get_property ("MIN_BRIGHTNESS", config.min_brightness);
00989 config.max_brightness =
00990 input.tag.get_property ("MAX_BRIGHTNESS", config.max_brightness);
00991 config.saturation =
00992 input.tag.get_property ("SATURATION", config.saturation);
00993 config.min_saturation =
00994 input.tag.get_property ("MIN_SATURATION", config.min_saturation);
00995 config.tolerance =
00996 input.tag.get_property ("TOLERANCE", config.tolerance);
00997 config.in_slope =
00998 input.tag.get_property ("IN_SLOPE", config.in_slope);
00999 config.out_slope =
01000 input.tag.get_property ("OUT_SLOPE", config.out_slope);
01001 config.alpha_offset =
01002 input.tag.get_property ("ALPHA_OFFSET", config.alpha_offset);
01003 config.spill_threshold =
01004 input.tag.get_property ("SPILL_THRESHOLD",
01005 config.spill_threshold);
01006 config.spill_amount =
01007 input.tag.get_property ("SPILL_AMOUNT", config.spill_amount);
01008 config.show_mask =
01009 input.tag.get_property ("SHOW_MASK", config.show_mask);
01010 }
01011 }
01012 }
01013
01014
01015 SHOW_GUI_MACRO(ChromaKeyHSV, ChromaKeyThread)
01016
01017 SET_STRING_MACRO(ChromaKeyHSV)
01018
01019 RAISE_WINDOW_MACRO(ChromaKeyHSV)
01020
01021 void ChromaKeyHSV::update_gui ()
01022 {
01023 if (thread)
01024 {
01025 load_configuration ();
01026 thread->window->lock_window ();
01027 thread->window->min_brightness->update (config.min_brightness);
01028 thread->window->max_brightness->update (config.max_brightness);
01029 thread->window->saturation->update (config.saturation);
01030 thread->window->min_saturation->update (config.min_saturation);
01031 thread->window->tolerance->update (config.tolerance);
01032 thread->window->in_slope->update (config.in_slope);
01033 thread->window->out_slope->update (config.out_slope);
01034 thread->window->alpha_offset->update (config.alpha_offset);
01035 thread->window->spill_threshold->update (config.spill_threshold);
01036 thread->window->spill_amount->update (config.spill_amount);
01037 thread->window->show_mask->update (config.show_mask);
01038 thread->window->update_sample ();
01039 thread->window->unlock_window ();
01040 }
01041 }
01042
01043
01044
01045
01046 int ChromaKeyHSV::handle_opengl()
01047 {
01048 #ifdef HAVE_GL
01049
01050 ChromaKeyHSV *plugin = this;
01051 OUTER_VARIABLES
01052
01053 static char *yuv_shader =
01054 "const vec3 black = vec3(0.0, 0.5, 0.5);\n"
01055 "\n"
01056 "vec4 yuv_to_rgb(vec4 color)\n"
01057 "{\n"
01058 YUV_TO_RGB_FRAG("color")
01059 " return color;\n"
01060 "}\n"
01061 "\n"
01062 "vec4 rgb_to_yuv(vec4 color)\n"
01063 "{\n"
01064 RGB_TO_YUV_FRAG("color")
01065 " return color;\n"
01066 "}\n";
01067
01068 static char *rgb_shader =
01069 "const vec3 black = vec3(0.0, 0.0, 0.0);\n"
01070 "\n"
01071 "vec4 yuv_to_rgb(vec4 color)\n"
01072 "{\n"
01073 " return color;\n"
01074 "}\n"
01075 "vec4 rgb_to_yuv(vec4 color)\n"
01076 "{\n"
01077 " return color;\n"
01078 "}\n";
01079
01080 static char *hsv_shader =
01081 "vec4 rgb_to_hsv(vec4 color)\n"
01082 "{\n"
01083 RGB_TO_HSV_FRAG("color")
01084 " return color;\n"
01085 "}\n"
01086 "\n"
01087 "vec4 hsv_to_rgb(vec4 color)\n"
01088 "{\n"
01089 HSV_TO_RGB_FRAG("color")
01090 " return color;\n"
01091 "}\n"
01092 "\n";
01093
01094 static char *show_rgbmask_shader =
01095 "vec4 show_mask(vec4 color, vec4 color2)\n"
01096 "{\n"
01097 " return vec4(1.0, 1.0, 1.0, min(color.a, color2.a));"
01098 "}\n";
01099
01100 static char *show_yuvmask_shader =
01101 "vec4 show_mask(vec4 color, vec4 color2)\n"
01102 "{\n"
01103 " return vec4(1.0, 0.5, 0.5, min(color.a, color2.a));"
01104 "}\n";
01105
01106 static char *nomask_shader =
01107 "vec4 show_mask(vec4 color, vec4 color2)\n"
01108 "{\n"
01109 " return vec4(color.rgb, min(color.a, color2.a));"
01110 "}\n";
01111
01112 extern unsigned char _binary_chromakey_sl_start[];
01113 static char *shader = (char*)_binary_chromakey_sl_start;
01114 SET_TRACE
01115
01116 get_output()->to_texture();
01117 get_output()->enable_opengl();
01118 get_output()->init_screen();
01119
01120 SET_TRACE
01121 char *shader_stack[] = { 0, 0, 0, 0, 0 };
01122
01123 SET_TRACE
01124 switch(get_output()->get_color_model())
01125 {
01126 case BC_YUV888:
01127 case BC_YUVA8888:
01128 shader_stack[0] = yuv_shader;
01129 shader_stack[1] = hsv_shader;
01130 if(config.show_mask)
01131 shader_stack[2] = show_yuvmask_shader;
01132 else
01133 shader_stack[2] = nomask_shader;
01134 shader_stack[3] = shader;
01135 break;
01136
01137 default:
01138 shader_stack[0] = rgb_shader;
01139 shader_stack[1] = hsv_shader;
01140 if(config.show_mask)
01141 shader_stack[2] = show_rgbmask_shader;
01142 else
01143 shader_stack[2] = nomask_shader;
01144 shader_stack[3] = shader;
01145 break;
01146 }
01147
01148
01149 SET_TRACE
01150 unsigned int frag = VFrame::make_shader(0,
01151 shader_stack[0],
01152 shader_stack[1],
01153 shader_stack[2],
01154 shader_stack[3],
01155 0);
01156
01157 SET_TRACE
01158 if(frag)
01159 {
01160 glUseProgram(frag);
01161 glUniform1i(glGetUniformLocation(frag, "tex"), 0);
01162 glUniform1f(glGetUniformLocation(frag, "red"), red);
01163 glUniform1f(glGetUniformLocation(frag, "green"), green);
01164 glUniform1f(glGetUniformLocation(frag, "blue"), blue);
01165 glUniform1f(glGetUniformLocation(frag, "in_slope"), in_slope);
01166 glUniform1f(glGetUniformLocation(frag, "out_slope"), out_slope);
01167 glUniform1f(glGetUniformLocation(frag, "tolerance"), tolerance);
01168 glUniform1f(glGetUniformLocation(frag, "tolerance_in"), tolerance_in);
01169 glUniform1f(glGetUniformLocation(frag, "tolerance_out"), tolerance_out);
01170 glUniform1f(glGetUniformLocation(frag, "sat"), sat);
01171 glUniform1f(glGetUniformLocation(frag, "min_s"), min_s);
01172 glUniform1f(glGetUniformLocation(frag, "min_s_in"), min_s_in);
01173 glUniform1f(glGetUniformLocation(frag, "min_s_out"), min_s_out);
01174 glUniform1f(glGetUniformLocation(frag, "min_v"), min_v);
01175 glUniform1f(glGetUniformLocation(frag, "min_v_in"), min_v_in);
01176 glUniform1f(glGetUniformLocation(frag, "min_v_out"), min_v_out);
01177 glUniform1f(glGetUniformLocation(frag, "max_v"), max_v);
01178 glUniform1f(glGetUniformLocation(frag, "max_v_in"), max_v_in);
01179 glUniform1f(glGetUniformLocation(frag, "max_v_out"), max_v_out);
01180 glUniform1f(glGetUniformLocation(frag, "spill_threshold"), spill_threshold);
01181 glUniform1f(glGetUniformLocation(frag, "spill_amount"), spill_amount);
01182 glUniform1f(glGetUniformLocation(frag, "alpha_offset"), alpha_offset);
01183 glUniform1f(glGetUniformLocation(frag, "hue_key"), hue_key);
01184 glUniform1f(glGetUniformLocation(frag, "saturation_key"), saturation_key);
01185 glUniform1f(glGetUniformLocation(frag, "value_key"), value_key);
01186 }
01187
01188 SET_TRACE
01189
01190 get_output()->bind_texture(0);
01191 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01192 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
01193
01194 if(cmodel_components(get_output()->get_color_model()) == 3)
01195 {
01196 glEnable(GL_BLEND);
01197 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
01198 get_output()->clear_pbuffer();
01199 }
01200 get_output()->draw_texture();
01201
01202 SET_TRACE
01203 glUseProgram(0);
01204 get_output()->set_opengl_state(VFrame::SCREEN);
01205 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
01206 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
01207 glDisable(GL_BLEND);
01208
01209 SET_TRACE
01210
01211 #endif
01212 }
01213