4 * Copyright (C) 2012 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "bcdisplayinfo.h"
23 #include "bcsignals.h"
24 #include "chromakey.h"
31 #include "loadbalance.h"
32 #include "playback3d.h"
34 #include "pluginvclient.h"
43 ChromaKeyConfig::ChromaKeyConfig ()
45 reset(RESET_DEFAULT_SETTINGS);
48 void ChromaKeyConfig::reset(int clear)
56 case RESET_MIN_BRIGHTNESS :
57 min_brightness = 50.0;
59 case RESET_MAX_BRIGHTNESS :
60 max_brightness = 100.0;
62 case RESET_TOLERANCE :
65 case RESET_SATURATION :
68 case RESET_MIN_SATURATION :
69 min_saturation = 50.0;
74 case RESET_OUT_SLOPE :
77 case RESET_ALPHA_OFFSET :
80 case RESET_SPILL_THRESHOLD :
81 spill_threshold = 0.0;
83 case RESET_SPILL_AMOUNT :
87 case RESET_DEFAULT_SETTINGS :
92 min_brightness = 50.0;
93 max_brightness = 100.0;
96 min_saturation = 50.0;
102 spill_threshold = 0.0;
111 void ChromaKeyConfig::copy_from (ChromaKeyConfig & src)
116 spill_threshold = src.spill_threshold;
117 spill_amount = src.spill_amount;
118 min_brightness = src.min_brightness;
119 max_brightness = src.max_brightness;
120 saturation = src.saturation;
121 min_saturation = src.min_saturation;
122 tolerance = src.tolerance;
123 in_slope = src.in_slope;
124 out_slope = src.out_slope;
125 alpha_offset = src.alpha_offset;
126 show_mask = src.show_mask;
129 int ChromaKeyConfig::equivalent (ChromaKeyConfig & src)
131 return (EQUIV (red, src.red) &&
132 EQUIV (green, src.green) &&
133 EQUIV (blue, src.blue) &&
134 EQUIV (spill_threshold, src.spill_threshold) &&
135 EQUIV (spill_amount, src.spill_amount) &&
136 EQUIV (min_brightness, src.min_brightness) &&
137 EQUIV (max_brightness, src.max_brightness) &&
138 EQUIV (saturation, src.saturation) &&
139 EQUIV (min_saturation, src.min_saturation) &&
140 EQUIV (tolerance, src.tolerance) &&
141 EQUIV (in_slope, src.in_slope) &&
142 EQUIV (out_slope, src.out_slope) &&
143 EQUIV (show_mask, src.show_mask) &&
144 EQUIV (alpha_offset, src.alpha_offset));
147 void ChromaKeyConfig::interpolate (ChromaKeyConfig & prev,
148 ChromaKeyConfig & next,
150 int64_t next_frame, int64_t current_frame)
153 (double) (current_frame - prev_frame) / (next_frame - prev_frame);
155 (double) (next_frame - current_frame) / (next_frame - prev_frame);
157 this->red = prev.red * prev_scale + next.red * next_scale;
158 this->green = prev.green * prev_scale + next.green * next_scale;
159 this->blue = prev.blue * prev_scale + next.blue * next_scale;
160 this->spill_threshold =
161 prev.spill_threshold * prev_scale + next.spill_threshold * next_scale;
163 prev.spill_amount * prev_scale + next.tolerance * next_scale;
164 this->min_brightness =
165 prev.min_brightness * prev_scale + next.min_brightness * next_scale;
166 this->max_brightness =
167 prev.max_brightness * prev_scale + next.max_brightness * next_scale;
169 prev.saturation * prev_scale + next.saturation * next_scale;
170 this->min_saturation =
171 prev.min_saturation * prev_scale + next.min_saturation * next_scale;
172 this->tolerance = prev.tolerance * prev_scale + next.tolerance * next_scale;
173 this->in_slope = prev.in_slope * prev_scale + next.in_slope * next_scale;
174 this->out_slope = prev.out_slope * prev_scale + next.out_slope * next_scale;
176 prev.alpha_offset * prev_scale + next.alpha_offset * next_scale;
177 this->show_mask = next.show_mask;
181 int ChromaKeyConfig::get_color ()
183 int red = (int) (CLIP (this->red, 0, 1) * 0xff);
184 int green = (int) (CLIP (this->green, 0, 1) * 0xff);
185 int blue = (int) (CLIP (this->blue, 0, 1) * 0xff);
186 return (red << 16) | (green << 8) | blue;
191 ChromaKeyWindow::ChromaKeyWindow (ChromaKeyHSV * plugin)
192 : PluginClientWindow(plugin,
199 this->plugin = plugin;
203 ChromaKeyWindow::~ChromaKeyWindow ()
208 void ChromaKeyWindow::create_objects ()
210 int xs10 = xS(10), xs20 = xS(20), xs100 = xS(100), xs200 = xS(200);
211 int ys10 = yS(10), ys20 = yS(20), ys30 = yS(30), ys40 = yS(40), ys50 = yS(50);
212 int y = ys10, x2 = xS(160), x3 = xS(260);
214 int clr_x = get_w()-x - xS(22); // note: clrBtn_w = 22
217 BC_TitleBar *title_bar;
221 add_subwindow(title_bar = new BC_TitleBar(x, y, get_w()-2*x, xs20, xs10, _("Color")));
224 add_subwindow (color = new ChromaKeyColor (plugin, this, x, y));
225 // Info for Sample rectangle: x_slider w_slider w_sample
227 add_subwindow (sample = new BC_SubWindow (x3 + xs200 - xs100, y, xs100, ys50));
229 add_subwindow (use_colorpicker = new ChromaKeyUseColorPicker (plugin, this, x, y));
231 add_subwindow (show_mask = new ChromaKeyShowMask (plugin, x, y));
233 // Key parameters section
235 add_subwindow(title_bar = new BC_TitleBar(x, y, get_w()-2*x, xs20, xs10, _("Key parameters")));
237 add_subwindow (title = new BC_Title (x, y, _("Hue Tolerance:")));
238 tolerance_text = new ChromaKeyFText(plugin, this,
239 0, &(plugin->config.tolerance), (x + x2), y, MIN_VALUE, MAX_VALUE);
240 tolerance_text->create_objects();
241 tolerance_slider = new ChromaKeyFSlider(plugin,
242 tolerance_text, &(plugin->config.tolerance), x3, y, MIN_VALUE, MAX_VALUE, xs200);
243 add_subwindow(tolerance_slider);
244 tolerance_text->slider = tolerance_slider;
245 clr_x = x3 + tolerance_slider->get_w() + x;
246 add_subwindow(tolerance_Clr = new ChromaKeyClr(plugin, this, clr_x, y, RESET_TOLERANCE));
249 add_subwindow (title = new BC_Title (x, y, _("Min. Brightness:")));
250 min_brightness_text = new ChromaKeyFText(plugin, this,
251 0, &(plugin->config.min_brightness), (x + x2), y,
252 MIN_VALUE, MAX_VALUE);
253 min_brightness_text->create_objects();
254 min_brightness_slider = new ChromaKeyFSlider(plugin,
255 min_brightness_text, &(plugin->config.min_brightness), x3, y, MIN_VALUE, MAX_VALUE, xs200);
256 add_subwindow(min_brightness_slider);
257 min_brightness_text->slider = min_brightness_slider;
258 add_subwindow(min_brightness_Clr = new ChromaKeyClr(plugin, this, clr_x, y, RESET_MIN_BRIGHTNESS));
261 add_subwindow (title = new BC_Title (x, y, _("Max. Brightness:")));
262 max_brightness_text = new ChromaKeyFText(plugin, this,
263 0, &(plugin->config.max_brightness), (x + x2), y, MIN_VALUE, MAX_VALUE);
264 max_brightness_text->create_objects();
265 max_brightness_slider = new ChromaKeyFSlider(plugin,
266 max_brightness_text, &(plugin->config.max_brightness), x3, y, MIN_VALUE, MAX_VALUE, xs200);
267 add_subwindow(max_brightness_slider);
268 max_brightness_text->slider = max_brightness_slider;
269 add_subwindow(max_brightness_Clr = new ChromaKeyClr(plugin, this, clr_x, y, RESET_MAX_BRIGHTNESS));
272 add_subwindow (title = new BC_Title (x, y, _("Saturation Offset:")));
273 saturation_text = new ChromaKeyFText(plugin, this,
274 0, &(plugin->config.saturation), (x + x2), y, MIN_VALUE, MAX_VALUE);
275 saturation_text->create_objects();
276 saturation_slider = new ChromaKeyFSlider(plugin,
277 saturation_text, &(plugin->config.saturation), x3, y, MIN_VALUE, MAX_VALUE, xs200);
278 add_subwindow(saturation_slider);
279 saturation_text->slider = saturation_slider;
280 add_subwindow(saturation_Clr = new ChromaKeyClr(plugin, this, clr_x, y, RESET_SATURATION));
283 add_subwindow (title = new BC_Title (x, y, _("Min Saturation:")));
284 min_saturation_text = new ChromaKeyFText(plugin, this,
285 0, &(plugin->config.min_saturation), (x + x2), y, MIN_VALUE, MAX_VALUE);
286 min_saturation_text->create_objects();
287 min_saturation_slider = new ChromaKeyFSlider(plugin,
288 min_saturation_text, &(plugin->config.min_saturation), x3, y, MIN_VALUE, MAX_VALUE, xs200);
289 add_subwindow(min_saturation_slider);
290 min_saturation_text->slider = min_saturation_slider;
291 add_subwindow(min_saturation_Clr = new ChromaKeyClr(plugin, this, clr_x, y, RESET_MIN_SATURATION));
294 // Mask tweaking section
295 add_subwindow(title_bar = new BC_TitleBar(x, y, get_w()-2*x, xs20, xs10, _("Mask tweaking")));
297 add_subwindow (title = new BC_Title (x, y, _("In Slope:")));
298 in_slope_text = new ChromaKeyFText(plugin, this,
299 0, &(plugin->config.in_slope), (x + x2), y, MIN_SLOPE, MAX_SLOPE);
300 in_slope_text->create_objects();
301 in_slope_slider = new ChromaKeyFSlider(plugin,
302 in_slope_text, &(plugin->config.in_slope), x3, y, MIN_SLOPE, MAX_SLOPE, xs200);
303 add_subwindow(in_slope_slider);
304 in_slope_text->slider = in_slope_slider;
305 add_subwindow(in_slope_Clr = new ChromaKeyClr(plugin, this, clr_x, y, RESET_IN_SLOPE));
308 add_subwindow (title = new BC_Title (x, y, _("Out Slope:")));
309 out_slope_text = new ChromaKeyFText(plugin, this,
310 0, &(plugin->config.out_slope), (x + x2), y, MIN_SLOPE, MAX_SLOPE);
311 out_slope_text->create_objects();
312 out_slope_slider = new ChromaKeyFSlider(plugin,
313 out_slope_text, &(plugin->config.out_slope), x3, y, MIN_SLOPE, MAX_SLOPE, xs200);
314 add_subwindow(out_slope_slider);
315 out_slope_text->slider = out_slope_slider;
316 add_subwindow(out_slope_Clr = new ChromaKeyClr(plugin, this, clr_x, y, RESET_OUT_SLOPE));
319 add_subwindow (title = new BC_Title (x, y, _("Alpha Offset:")));
320 alpha_offset_text = new ChromaKeyFText(plugin, this,
321 0, &(plugin->config.alpha_offset), (x + x2), y, -MAX_ALPHA, MAX_ALPHA);
322 alpha_offset_text->create_objects();
323 alpha_offset_slider = new ChromaKeyFSlider(plugin,
324 alpha_offset_text, &(plugin->config.alpha_offset), x3, y, -MAX_ALPHA, MAX_ALPHA, xs200);
325 add_subwindow(alpha_offset_slider);
326 alpha_offset_text->slider = alpha_offset_slider;
327 add_subwindow(alpha_offset_Clr = new ChromaKeyClr(plugin, this, clr_x, y, RESET_ALPHA_OFFSET));
330 // Spill light control section
331 add_subwindow(title_bar = new BC_TitleBar(x, y, get_w()-2*x, xs20, xs10, _("Spill light control")));
333 add_subwindow (title = new BC_Title (x, y, _("Spill Threshold:")));
334 spill_threshold_text = new ChromaKeyFText(plugin, this,
335 0, &(plugin->config.spill_threshold), (x + x2), y, MIN_VALUE, MAX_VALUE);
336 spill_threshold_text->create_objects();
337 spill_threshold_slider = new ChromaKeyFSlider(plugin,
338 spill_threshold_text, &(plugin->config.spill_threshold), x3, y, MIN_VALUE, MAX_VALUE, xs200);
339 add_subwindow(spill_threshold_slider);
340 spill_threshold_text->slider = spill_threshold_slider;
341 add_subwindow(spill_threshold_Clr = new ChromaKeyClr(plugin, this, clr_x, y, RESET_SPILL_THRESHOLD));
344 add_subwindow (title = new BC_Title (x, y, _("Spill Compensation:")));
345 spill_amount_text = new ChromaKeyFText(plugin, this,
346 0, &(plugin->config.spill_amount), (x + x2), y, MIN_VALUE, MAX_VALUE);
347 spill_amount_text->create_objects();
348 spill_amount_slider = new ChromaKeyFSlider(plugin,
349 spill_amount_text, &(plugin->config.spill_amount), x3, y, MIN_VALUE, MAX_VALUE, xs200);
350 add_subwindow(spill_amount_slider);
351 spill_amount_text->slider = spill_amount_slider;
352 add_subwindow(spill_amount_Clr = new ChromaKeyClr(plugin, this, clr_x, y, RESET_SPILL_AMOUNT));
356 add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x));
358 add_subwindow(reset = new ChromaKeyReset(plugin, this, x, y));
360 color_thread = new ChromaKeyColorThread (plugin, this);
366 void ChromaKeyWindow::update_sample()
368 sample->set_color (plugin->config.get_color ());
369 sample->draw_box (0, 0, sample->get_w (), sample->get_h ());
370 sample->set_color (BLACK);
371 sample->draw_rectangle (0, 0, sample->get_w (), sample->get_h ());
375 void ChromaKeyWindow::done_event(int result)
377 color_thread->close_window();
381 ChromaKeyColor::ChromaKeyColor (ChromaKeyHSV * plugin,
382 ChromaKeyWindow * gui, int x, int y):
383 BC_GenericButton (x, y, _("Color..."))
385 this->plugin = plugin;
389 int ChromaKeyColor::handle_event ()
391 gui->color_thread->start_window (plugin->config.get_color (), 0xff);
397 ChromaKeyFText::ChromaKeyFText(ChromaKeyHSV *plugin, ChromaKeyWindow *gui,
398 ChromaKeyFSlider *slider, float *output, int x, int y, float min, float max)
399 : BC_TumbleTextBox(gui, *output,
400 min, max, x, y, xS(60), 2)
402 this->plugin = plugin;
404 this->output = output;
405 this->slider = slider;
411 ChromaKeyFText::~ChromaKeyFText()
415 int ChromaKeyFText::handle_event()
417 *output = atof(get_text());
418 if(*output > max) *output = max;
419 else if(*output < min) *output = min;
420 slider->update(*output);
421 plugin->send_configure_change();
425 ChromaKeyFSlider::ChromaKeyFSlider(ChromaKeyHSV *plugin,
426 ChromaKeyFText *text, float *output, int x, int y,
427 float min, float max, int w)
428 : BC_FSlider(x, y, 0, w, w, min, max, *output)
430 this->plugin = plugin;
431 this->output = output;
433 set_precision (0.01);
434 enable_show_value(0); // Hide caption
437 ChromaKeyFSlider::~ChromaKeyFSlider()
441 int ChromaKeyFSlider::handle_event()
443 *output = get_value();
444 text->update(*output);
445 plugin->send_configure_change();
449 ChromaKeyClr::ChromaKeyClr(ChromaKeyHSV *plugin, ChromaKeyWindow *gui, int x, int y, int clear)
450 : BC_Button(x, y, plugin->get_theme()->get_image_set("reset_button"))
452 this->plugin = plugin;
457 ChromaKeyClr::~ChromaKeyClr()
461 int ChromaKeyClr::handle_event()
463 plugin->config.reset(clear);
464 gui->update_gui(clear);
465 plugin->send_configure_change();
472 ChromaKeyShowMask::ChromaKeyShowMask (ChromaKeyHSV * plugin, int x, int y):BC_CheckBox (x, y, plugin->config.show_mask,
476 this->plugin = plugin;
480 int ChromaKeyShowMask::handle_event ()
482 plugin->config.show_mask = get_value ();
483 plugin->send_configure_change ();
487 ChromaKeyReset::ChromaKeyReset (ChromaKeyHSV *plugin, ChromaKeyWindow *gui, int x, int y)
488 :BC_GenericButton(x, y, _("Reset"))
490 this->plugin = plugin;
494 int ChromaKeyReset::handle_event()
496 plugin->config.reset(RESET_DEFAULT_SETTINGS);
497 gui->update_gui(RESET_DEFAULT_SETTINGS);
498 plugin->send_configure_change();
502 ChromaKeyUseColorPicker::ChromaKeyUseColorPicker (ChromaKeyHSV * plugin, ChromaKeyWindow * gui, int x, int y)
503 : BC_GenericButton (x, y,
505 ("Use color picker"))
507 this->plugin = plugin;
511 int ChromaKeyUseColorPicker::handle_event ()
513 plugin->config.red = plugin->get_red ();
514 plugin->config.green = plugin->get_green ();
515 plugin->config.blue = plugin->get_blue ();
517 gui->update_sample ();
520 plugin->send_configure_change ();
529 ChromaKeyColorThread::ChromaKeyColorThread (ChromaKeyHSV * plugin, ChromaKeyWindow * gui)
530 : ColorPicker (1, _("Inner color"))
532 this->plugin = plugin;
536 int ChromaKeyColorThread::handle_new_color (int output, int alpha)
538 plugin->config.red = (float) (output & 0xff0000) / 0xff0000;
539 plugin->config.green = (float) (output & 0xff00) / 0xff00;
540 plugin->config.blue = (float) (output & 0xff) / 0xff;
542 get_gui()->unlock_window();
543 gui->lock_window("ChromaKeyColorThread::handle_new_color");
544 gui->update_sample ();
545 gui->unlock_window();
546 get_gui()->lock_window("ChromaKeyColorThread::handle_new_color");
549 plugin->send_configure_change ();
560 ChromaKeyServer::ChromaKeyServer (ChromaKeyHSV * plugin):LoadServer (plugin->PluginClient::smp + 1,
561 plugin->PluginClient::smp +
564 this->plugin = plugin;
567 void ChromaKeyServer::init_packages ()
569 for (int i = 0; i < get_total_packages (); i++)
571 ChromaKeyPackage *pkg = (ChromaKeyPackage *) get_package (i);
572 pkg->y1 = plugin->input->get_h () * i / get_total_packages ();
573 pkg->y2 = plugin->input->get_h () * (i + 1) / get_total_packages ();
578 ChromaKeyServer::new_client ()
580 return new ChromaKeyUnit (plugin, this);
584 ChromaKeyServer::new_package ()
586 return new ChromaKeyPackage;
591 ChromaKeyPackage::ChromaKeyPackage ():LoadPackage ()
595 ChromaKeyUnit::ChromaKeyUnit (ChromaKeyHSV * plugin, ChromaKeyServer * server):LoadClient
598 this->plugin = plugin;
604 #define ABS(a) ((a<0)?-(a):a)
605 // Reuse as much as possible in the opengl version
606 #define OUTER_VARIABLES \
607 float red = plugin->config.red; \
608 float green = plugin->config.green; \
609 float blue = plugin->config.blue; \
611 float in_slope = plugin->config.in_slope / 100; \
612 float out_slope = plugin->config.out_slope / 100; \
614 float tolerance = plugin->config.tolerance / 100; \
615 float tolerance_in = tolerance - in_slope; \
616 float tolerance_out = tolerance + out_slope; \
618 float sat = plugin->config.saturation / 100; \
619 float min_s = plugin->config.min_saturation / 100; \
620 float min_s_in = min_s + in_slope; \
621 float min_s_out = min_s - out_slope; \
623 float min_v = plugin->config.min_brightness / 100; \
624 float min_v_in = min_v + in_slope; \
625 float min_v_out = min_v - out_slope; \
627 float max_v = plugin->config.max_brightness / 100; \
628 float max_v_in = max_v - in_slope; \
629 float max_v_out = max_v + out_slope; \
631 float spill_threshold = plugin->config.spill_threshold / 100; \
632 float spill_amount = 1.0 - plugin->config.spill_amount / 100; \
634 float alpha_offset = plugin->config.alpha_offset / 100; \
636 /* Convert RGB key to HSV key */ \
637 float hue_key, saturation_key, value_key; \
638 HSV::rgb_to_hsv(red, \
646 template <typename component_type>
647 void ChromaKeyUnit::process_chromakey(int components,
650 ChromaKeyPackage *pkg)
654 int w = plugin->input->get_w();
656 for (int i = pkg->y1; i < pkg->y2; i++)
658 component_type *row = (component_type *) plugin->input->get_rows ()[i];
660 for (int j = 0; j < w; j++)
662 float r, g, b, a = 1;
664 r = (float) row[0] / max;
665 g = (float) row[1] / max;
666 b = (float) row[2] / max;
669 YUV::yuv.yuv_to_rgb_f (r, g, b, row[0], row[1], row[2]);
673 float av = 1, ah = 1, as = 1, avm = 1;
674 bool has_match = true;
676 HSV::rgb_to_hsv (r, g, b, h, s, v);
678 // First, test if the hue is in range
681 if(h <= hue_key - tolerance_in * 180.0)
684 if(h >= hue_key + tolerance_in * 180.0)
691 if (ABS (h - hue_key) < tolerance_in * 180)
694 if ((out_slope != 0) && (ABS (h - hue_key) < tolerance * 180))
695 /* we scale alpha between 0 and 1/2 */
696 ah = ABS (h - hue_key) / tolerance / 360;
698 if (ABS (h - hue_key) < tolerance_out * 180)
699 /* we scale alpha between 1/2 and 1 */
700 ah = ABS (h - hue_key) / tolerance_out / 360;
704 // Check if the saturation matches
709 else if (s - sat >= min_s_in)
711 else if ((out_slope != 0) && (s - sat > min_s))
712 as = (s - sat - min_s) / (min_s * 2);
713 else if (s - sat > min_s_out)
714 as = (s - sat - min_s_out) / (min_s_out * 2);
719 // Check if the value is more than the minimun
724 else if (v >= min_v_in)
726 else if ((out_slope != 0) && (v > min_v))
727 av = (v - min_v) / (min_v * 2);
728 else if (v > min_v_out)
729 av = (v - min_v_out) / (min_v_out * 2);
734 // Check if the value is less than the maximum
739 else if (v <= max_v_in)
741 else if ((out_slope != 0) && (v < max_v))
742 avm = (v - max_v) / (max_v * 2);
743 else if (v < max_v_out)
744 avm = (v - max_v_out) / (max_v_out * 2);
749 // If the color is part of the key, update the alpha channel
751 a = MAX (MAX (ah, av), MAX (as, avm));
753 // Spill light processing
754 if ((ABS (h - hue_key) < spill_threshold * 180) ||
755 ((ABS (h - hue_key) > 360)
756 && (ABS (h - hue_key) - 360 < spill_threshold * 180)))
758 s = s * spill_amount * ABS (h - hue_key) / (spill_threshold * 180);
760 HSV::hsv_to_rgb (r, g, b, h, s, v);
763 row[0] = (component_type) ((float) r * max);
764 row[1] = (component_type) ((float) g * max);
765 row[2] = (component_type) ((float) b * max);
768 YUV::yuv.rgb_to_yuv_f(r, g, b, row[0], row[1], row[2]);
774 if (plugin->config.show_mask)
779 row[0] = (component_type) ((float) a * max);
780 row[1] = (component_type) ((float) max / 2);
781 row[2] = (component_type) ((float) max / 2);
785 row[0] = (component_type) ((float) a * max);
786 row[1] = (component_type) ((float) a * max);
787 row[2] = (component_type) ((float) a * max);
791 /* Multiply alpha and put back in frame */
794 row[3] = MIN ((component_type) (a * max), row[3]);
798 row[0] = (component_type) ((float) a * row[0]);
800 (component_type) ((float) a * (row[1] - (max / 2 + 1)) +
803 (component_type) ((float) a * (row[2] - (max / 2 + 1)) +
808 row[0] = (component_type) ((float) a * row[0]);
809 row[1] = (component_type) ((float) a * row[1]);
810 row[2] = (component_type) ((float) a * row[2]);
821 void ChromaKeyUnit::process_package(LoadPackage *package)
823 ChromaKeyPackage *pkg = (ChromaKeyPackage*)package;
826 switch(plugin->input->get_color_model())
829 process_chromakey<float> (3, 1.0, 0, pkg);
832 process_chromakey<float> ( 4, 1.0, 0, pkg);
835 process_chromakey<unsigned char> ( 3, 0xff, 0, pkg);
838 process_chromakey<unsigned char> ( 4, 0xff, 0, pkg);
841 process_chromakey<unsigned char> ( 3, 0xff, 1, pkg);
844 process_chromakey<unsigned char> ( 4, 0xff, 1, pkg);
847 process_chromakey<uint16_t> (3, 0xffff, 1, pkg);
849 case BC_YUVA16161616:
850 process_chromakey<uint16_t> (4, 0xffff, 1, pkg);
860 REGISTER_PLUGIN(ChromaKeyHSV)
864 ChromaKeyHSV::ChromaKeyHSV(PluginServer *server)
865 : PluginVClient(server)
871 ChromaKeyHSV::~ChromaKeyHSV()
874 if(engine) delete engine;
878 int ChromaKeyHSV::process_buffer(VFrame *frame,
879 int64_t start_position,
882 load_configuration();
884 this->output = frame;
892 if(get_use_opengl()) return run_opengl();
895 if(!engine) engine = new ChromaKeyServer(this);
896 engine->process_packages();
901 const char* ChromaKeyHSV::plugin_title() { return N_("Chroma key (HSV)"); }
902 int ChromaKeyHSV::is_realtime() { return 1; }
905 LOAD_CONFIGURATION_MACRO(ChromaKeyHSV, ChromaKeyConfig)
908 void ChromaKeyHSV::save_data(KeyFrame * keyframe)
911 output.set_shared_output(keyframe->xbuf);
912 output.tag.set_title("CHROMAKEY_HSV");
913 output.tag.set_property("RED", config.red);
914 output.tag.set_property("GREEN", config.green);
915 output.tag.set_property("BLUE", config.blue);
916 output.tag.set_property("MIN_BRIGHTNESS", config.min_brightness);
917 output.tag.set_property("MAX_BRIGHTNESS", config.max_brightness);
918 output.tag.set_property("SATURATION", config.saturation);
919 output.tag.set_property("MIN_SATURATION", config.min_saturation);
920 output.tag.set_property("TOLERANCE", config.tolerance);
921 output.tag.set_property("IN_SLOPE", config.in_slope);
922 output.tag.set_property("OUT_SLOPE", config.out_slope);
923 output.tag.set_property("ALPHA_OFFSET", config.alpha_offset);
924 output.tag.set_property("SPILL_THRESHOLD", config.spill_threshold);
925 output.tag.set_property("SPILL_AMOUNT", config.spill_amount);
926 output.tag.set_property("SHOW_MASK", config.show_mask);
928 output.tag.set_title("/CHROMAKEY_HSV");
930 output.append_newline();
931 output.terminate_string();
934 void ChromaKeyHSV::read_data(KeyFrame * keyframe)
938 input.set_shared_input(keyframe->xbuf);
940 while( !input.read_tag() ) {
941 if( input.tag.title_is("CHROMAKEY_HSV") ) {
942 config.red = input.tag.get_property("RED", config.red);
943 config.green = input.tag.get_property("GREEN", config.green);
944 config.blue = input.tag.get_property("BLUE", config.blue);
945 config.min_brightness =
946 input.tag.get_property("MIN_BRIGHTNESS", config.min_brightness);
947 config.max_brightness =
948 input.tag.get_property("MAX_BRIGHTNESS", config.max_brightness);
950 input.tag.get_property("SATURATION", config.saturation);
951 config.min_saturation =
952 input.tag.get_property("MIN_SATURATION", config.min_saturation);
954 input.tag.get_property("TOLERANCE", config.tolerance);
956 input.tag.get_property("IN_SLOPE", config.in_slope);
958 input.tag.get_property("OUT_SLOPE", config.out_slope);
959 config.alpha_offset =
960 input.tag.get_property("ALPHA_OFFSET", config.alpha_offset);
961 config.spill_threshold =
962 input.tag.get_property("SPILL_THRESHOLD",
963 config.spill_threshold);
964 config.spill_amount =
965 input.tag.get_property("SPILL_AMOUNT", config.spill_amount);
967 input.tag.get_property("SHOW_MASK", config.show_mask);
973 NEW_WINDOW_MACRO(ChromaKeyHSV, ChromaKeyWindow)
975 void ChromaKeyHSV::update_gui()
978 load_configuration();
979 ChromaKeyWindow *window = (ChromaKeyWindow*)thread->window;
980 window->lock_window();
981 window->update_gui(RESET_ALL);
982 window->unlock_window();
986 void ChromaKeyWindow::update_gui(int clear)
988 ChromaKeyConfig &config = plugin->config;
993 case RESET_MIN_BRIGHTNESS :
994 min_brightness_text->update(config.min_brightness);
995 min_brightness_slider->update(config.min_brightness);
997 case RESET_MAX_BRIGHTNESS :
998 max_brightness_text->update(config.max_brightness);
999 max_brightness_slider->update(config.max_brightness);
1001 case RESET_TOLERANCE :
1002 tolerance_text->update(config.tolerance);
1003 tolerance_slider->update(config.tolerance);
1005 case RESET_SATURATION :
1006 saturation_text->update(config.saturation);
1007 saturation_slider->update(config.saturation);
1009 case RESET_MIN_SATURATION :
1010 min_saturation_text->update(config.min_saturation);
1011 min_saturation_slider->update(config.min_saturation);
1013 case RESET_IN_SLOPE :
1014 in_slope_text->update(config.in_slope);
1015 in_slope_slider->update(config.in_slope);
1017 case RESET_OUT_SLOPE :
1018 out_slope_text->update(config.out_slope);
1019 out_slope_slider->update(config.out_slope);
1021 case RESET_ALPHA_OFFSET :
1022 alpha_offset_text->update(config.alpha_offset);
1023 alpha_offset_slider->update(config.alpha_offset);
1025 case RESET_SPILL_THRESHOLD :
1026 spill_threshold_text->update(config.spill_threshold);
1027 spill_threshold_slider->update(config.spill_threshold);
1029 case RESET_SPILL_AMOUNT :
1030 spill_amount_text->update(config.spill_amount);
1031 spill_amount_slider->update(config.spill_amount);
1034 case RESET_DEFAULT_SETTINGS :
1036 min_brightness_text->update(config.min_brightness);
1037 min_brightness_slider->update(config.min_brightness);
1038 max_brightness_text->update(config.max_brightness);
1039 max_brightness_slider->update(config.max_brightness);
1040 tolerance_text->update(config.tolerance);
1041 tolerance_slider->update(config.tolerance);
1042 saturation_text->update(config.saturation);
1043 saturation_slider->update(config.saturation);
1044 min_saturation_text->update(config.min_saturation);
1045 min_saturation_slider->update(config.min_saturation);
1046 in_slope_text->update(config.in_slope);
1047 in_slope_slider->update(config.in_slope);
1048 out_slope_text->update(config.out_slope);
1049 out_slope_slider->update(config.out_slope);
1050 alpha_offset_text->update(config.alpha_offset);
1051 alpha_offset_slider->update(config.alpha_offset);
1052 spill_threshold_text->update(config.spill_threshold);
1053 spill_threshold_slider->update(config.spill_threshold);
1054 spill_amount_text->update(config.spill_amount);
1055 spill_amount_slider->update(config.spill_amount);
1056 show_mask->update(config.show_mask);
1064 int ChromaKeyHSV::handle_opengl()
1068 ChromaKeyHSV *plugin = this;
1071 static const char *yuv_shader =
1072 "const vec3 black = vec3(0.0, 0.5, 0.5);\n"
1073 "uniform mat3 yuv_to_rgb_matrix;\n"
1074 "uniform mat3 rgb_to_yuv_matrix;\n"
1075 "uniform float yminf;\n"
1077 "vec4 yuv_to_rgb(vec4 color)\n"
1079 " color.rgb -= vec3(yminf, 0.5, 0.5);\n"
1080 " color.rgb = yuv_to_rgb_matrix * color.rgb;\n"
1084 "vec4 rgb_to_yuv(vec4 color)\n"
1086 " color.rgb = rgb_to_yuv_matrix * color.rgb;\n"
1087 " color.rgb += vec3(yminf, 0.5, 0.5);\n"
1091 static const char *rgb_shader =
1092 "const vec3 black = vec3(0.0, 0.0, 0.0);\n"
1094 "vec4 yuv_to_rgb(vec4 color)\n"
1098 "vec4 rgb_to_yuv(vec4 color)\n"
1103 static const char *hsv_shader =
1104 "vec4 rgb_to_hsv(vec4 color)\n"
1106 RGB_TO_HSV_FRAG("color")
1110 "vec4 hsv_to_rgb(vec4 color)\n"
1112 HSV_TO_RGB_FRAG("color")
1117 static const char *show_rgbmask_shader =
1118 "vec4 show_mask(vec4 color, vec4 color2)\n"
1120 " return vec4(1.0, 1.0, 1.0, min(color.a, color2.a));"
1123 static const char *show_yuvmask_shader =
1124 "vec4 show_mask(vec4 color, vec4 color2)\n"
1126 " return vec4(1.0, 0.5, 0.5, min(color.a, color2.a));"
1129 static const char *nomask_shader =
1130 "vec4 show_mask(vec4 color, vec4 color2)\n"
1132 " return vec4(color.rgb, min(color.a, color2.a));"
1135 get_output()->to_texture();
1136 get_output()->enable_opengl();
1137 get_output()->init_screen();
1139 const char *shader_stack[16];
1140 memset(shader_stack,0, sizeof(shader_stack));
1141 int current_shader = 0;
1143 shader_stack[current_shader++] = \
1144 !BC_CModels::is_yuv(get_output()->get_color_model()) ?
1145 rgb_shader : yuv_shader;
1146 shader_stack[current_shader++] = hsv_shader;
1147 shader_stack[current_shader++] = !config.show_mask ? nomask_shader :
1148 !BC_CModels::is_yuv(get_output()->get_color_model()) ?
1149 show_rgbmask_shader : show_yuvmask_shader ;
1150 extern unsigned char _binary_chromakey_sl_start[];
1151 static const char *shader_frag = (char*)_binary_chromakey_sl_start;
1152 shader_stack[current_shader++] = shader_frag;
1154 shader_stack[current_shader] = 0;
1155 unsigned int shader = VFrame::make_shader(shader_stack);
1157 glUseProgram(shader);
1158 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
1159 glUniform1f(glGetUniformLocation(shader, "red"), red);
1160 glUniform1f(glGetUniformLocation(shader, "green"), green);
1161 glUniform1f(glGetUniformLocation(shader, "blue"), blue);
1162 glUniform1f(glGetUniformLocation(shader, "in_slope"), in_slope);
1163 glUniform1f(glGetUniformLocation(shader, "out_slope"), out_slope);
1164 glUniform1f(glGetUniformLocation(shader, "tolerance"), tolerance);
1165 glUniform1f(glGetUniformLocation(shader, "tolerance_in"), tolerance_in);
1166 glUniform1f(glGetUniformLocation(shader, "tolerance_out"), tolerance_out);
1167 glUniform1f(glGetUniformLocation(shader, "sat"), sat);
1168 glUniform1f(glGetUniformLocation(shader, "min_s"), min_s);
1169 glUniform1f(glGetUniformLocation(shader, "min_s_in"), min_s_in);
1170 glUniform1f(glGetUniformLocation(shader, "min_s_out"), min_s_out);
1171 glUniform1f(glGetUniformLocation(shader, "min_v"), min_v);
1172 glUniform1f(glGetUniformLocation(shader, "min_v_in"), min_v_in);
1173 glUniform1f(glGetUniformLocation(shader, "min_v_out"), min_v_out);
1174 glUniform1f(glGetUniformLocation(shader, "max_v"), max_v);
1175 glUniform1f(glGetUniformLocation(shader, "max_v_in"), max_v_in);
1176 glUniform1f(glGetUniformLocation(shader, "max_v_out"), max_v_out);
1177 glUniform1f(glGetUniformLocation(shader, "spill_threshold"), spill_threshold);
1178 glUniform1f(glGetUniformLocation(shader, "spill_amount"), spill_amount);
1179 glUniform1f(glGetUniformLocation(shader, "alpha_offset"), alpha_offset);
1180 glUniform1f(glGetUniformLocation(shader, "hue_key"), hue_key);
1181 glUniform1f(glGetUniformLocation(shader, "saturation_key"), saturation_key);
1182 glUniform1f(glGetUniformLocation(shader, "value_key"), value_key);
1183 if( BC_CModels::is_yuv(get_output()->get_color_model()) )
1184 BC_GL_COLORS(shader);
1187 get_output()->bind_texture(0);
1188 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1189 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1191 if(BC_CModels::components(get_output()->get_color_model()) == 3)
1194 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1195 get_output()->clear_pbuffer();
1197 get_output()->draw_texture();
1200 get_output()->set_opengl_state(VFrame::SCREEN);
1201 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1202 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1203 glDisable(GL_BLEND);