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 ()
48 void ChromaKeyConfig::reset()
55 min_brightness = 50.0;
56 max_brightness = 100.0;
59 min_saturation = 50.0;
65 spill_threshold = 0.0;
74 ChromaKeyConfig::copy_from (ChromaKeyConfig & src)
79 spill_threshold = src.spill_threshold;
80 spill_amount = src.spill_amount;
81 min_brightness = src.min_brightness;
82 max_brightness = src.max_brightness;
83 saturation = src.saturation;
84 min_saturation = src.min_saturation;
85 tolerance = src.tolerance;
86 in_slope = src.in_slope;
87 out_slope = src.out_slope;
88 alpha_offset = src.alpha_offset;
89 show_mask = src.show_mask;
93 ChromaKeyConfig::equivalent (ChromaKeyConfig & src)
95 return (EQUIV (red, src.red) &&
96 EQUIV (green, src.green) &&
97 EQUIV (blue, src.blue) &&
98 EQUIV (spill_threshold, src.spill_threshold) &&
99 EQUIV (spill_amount, src.spill_amount) &&
100 EQUIV (min_brightness, src.min_brightness) &&
101 EQUIV (max_brightness, src.max_brightness) &&
102 EQUIV (saturation, src.saturation) &&
103 EQUIV (min_saturation, src.min_saturation) &&
104 EQUIV (tolerance, src.tolerance) &&
105 EQUIV (in_slope, src.in_slope) &&
106 EQUIV (out_slope, src.out_slope) &&
107 EQUIV (show_mask, src.show_mask) &&
108 EQUIV (alpha_offset, src.alpha_offset));
112 ChromaKeyConfig::interpolate (ChromaKeyConfig & prev,
113 ChromaKeyConfig & next,
115 int64_t next_frame, int64_t current_frame)
118 (double) (current_frame - prev_frame) / (next_frame - prev_frame);
120 (double) (next_frame - current_frame) / (next_frame - prev_frame);
122 this->red = prev.red * prev_scale + next.red * next_scale;
123 this->green = prev.green * prev_scale + next.green * next_scale;
124 this->blue = prev.blue * prev_scale + next.blue * next_scale;
125 this->spill_threshold =
126 prev.spill_threshold * prev_scale + next.spill_threshold * next_scale;
128 prev.spill_amount * prev_scale + next.tolerance * next_scale;
129 this->min_brightness =
130 prev.min_brightness * prev_scale + next.min_brightness * next_scale;
131 this->max_brightness =
132 prev.max_brightness * prev_scale + next.max_brightness * next_scale;
134 prev.saturation * prev_scale + next.saturation * next_scale;
135 this->min_saturation =
136 prev.min_saturation * prev_scale + next.min_saturation * next_scale;
137 this->tolerance = prev.tolerance * prev_scale + next.tolerance * next_scale;
138 this->in_slope = prev.in_slope * prev_scale + next.in_slope * next_scale;
139 this->out_slope = prev.out_slope * prev_scale + next.out_slope * next_scale;
141 prev.alpha_offset * prev_scale + next.alpha_offset * next_scale;
142 this->show_mask = next.show_mask;
147 ChromaKeyConfig::get_color ()
149 int red = (int) (CLIP (this->red, 0, 1) * 0xff);
150 int green = (int) (CLIP (this->green, 0, 1) * 0xff);
151 int blue = (int) (CLIP (this->blue, 0, 1) * 0xff);
152 return (red << 16) | (green << 8) | blue;
157 ChromaKeyWindow::ChromaKeyWindow (ChromaKeyHSV * plugin)
158 : PluginClientWindow(plugin,
165 this->plugin = plugin;
169 ChromaKeyWindow::~ChromaKeyWindow ()
175 ChromaKeyWindow::create_objects ()
177 int xs5 = xS(5), xs10 = xS(10), xs30 = xS(30), xs100 = xS(100), xs240 = xS(240);
178 int ys5 = yS(5), ys10 = yS(10), ys25 = yS(25), ys50 = yS(50);
179 int y = ys10, y1, x1 = 0, x2 = xs10;
184 int ymargin = get_text_height(MEDIUMFONT) + xs5;
185 int ymargin2 = get_text_height(MEDIUMFONT) + ys10;
187 add_subwindow (title = new BC_Title (x2, y, _("Color:")));
189 add_subwindow (color = new ChromaKeyColor (plugin, this, x, y + ys25));
191 add_subwindow (sample =
192 new BC_SubWindow (x + color->get_w () + xs10, y, xs100, ys50));
193 y += sample->get_h () + ys10;
195 add_subwindow (use_colorpicker =
196 new ChromaKeyUseColorPicker (plugin, this, x, y));
197 y += use_colorpicker->get_h() + ys10;
199 add_subwindow (new ChromaKeyReset (plugin, this, x2+xs240, y));
200 add_subwindow (show_mask = new ChromaKeyShowMask (plugin, x2, y));
201 y += show_mask->get_h() + ys5;
203 add_subwindow(bar = new BC_Bar(x2, y, get_w() - x2 * 2));
204 y += bar->get_h() + ys5;
206 add_subwindow (new BC_Title (x2, y, _("Key parameters:")));
208 add_subwindow (title = new BC_Title (x, y, _("Hue Tolerance:")));
209 if(title->get_w() > x1) x1 = title->get_w();
211 add_subwindow (title = new BC_Title (x, y, _("Min. Brightness:")));
212 if(title->get_w() > x1) x1 = title->get_w();
214 add_subwindow (title = new BC_Title (x, y, _("Max. Brightness:")));
215 if(title->get_w() > x1) x1 = title->get_w();
217 add_subwindow (title = new BC_Title (x, y, _("Saturation Offset:")));
218 if(title->get_w() > x1) x1 = title->get_w();
220 add_subwindow (title = new BC_Title (x, y, _("Min Saturation:")));
221 if(title->get_w() > x1) x1 = title->get_w();
224 add_subwindow(bar = new BC_Bar(x2, y, get_w() - x2 * 2));
225 y += bar->get_h() + ys5;
226 add_subwindow (title = new BC_Title (x2, y, _("Mask tweaking:")));
228 add_subwindow (title = new BC_Title (x, y, _("In Slope:")));
229 if(title->get_w() > x1) x1 = title->get_w();
231 add_subwindow (title = new BC_Title (x, y, _("Out Slope:")));
232 if(title->get_w() > x1) x1 = title->get_w();
234 add_subwindow (title = new BC_Title (x, y, _("Alpha Offset:")));
235 if(title->get_w() > x1) x1 = title->get_w();
240 add_subwindow(bar = new BC_Bar(x2, y, get_w() - x2 * 2));
241 y += bar->get_h() + ys5;
242 add_subwindow (title = new BC_Title (x2, y, _("Spill light control:")));
244 add_subwindow (title = new BC_Title (x, y, _("Spill Threshold:")));
245 if(title->get_w() > x1) x1 = title->get_w();
247 add_subwindow (title = new BC_Title (x, y, _("Spill Compensation:")));
248 if(title->get_w() > x1) x1 = title->get_w();
258 add_subwindow (tolerance = new ChromaKeyTolerance (plugin, x1, y));
260 add_subwindow (min_brightness = new ChromaKeyMinBrightness (plugin, x1, y));
262 add_subwindow (max_brightness = new ChromaKeyMaxBrightness (plugin, x1, y));
264 add_subwindow (saturation = new ChromaKeySaturation (plugin, x1, y));
266 add_subwindow (min_saturation = new ChromaKeyMinSaturation (plugin, x1, y));
269 y += bar->get_h() + ys5;
271 add_subwindow (in_slope = new ChromaKeyInSlope (plugin, x1, y));
273 add_subwindow (out_slope = new ChromaKeyOutSlope (plugin, x1, y));
275 add_subwindow (alpha_offset = new ChromaKeyAlphaOffset (plugin, x1, y));
278 y += bar->get_h() + ys5;
280 add_subwindow (spill_threshold = new ChromaKeySpillThreshold (plugin, x1, y));
282 add_subwindow (spill_amount = new ChromaKeySpillAmount (plugin, x1, y));
284 color_thread = new ChromaKeyColorThread (plugin, this);
291 ChromaKeyWindow::update_sample ()
293 sample->set_color (plugin->config.get_color ());
294 sample->draw_box (0, 0, sample->get_w (), sample->get_h ());
295 sample->set_color (BLACK);
296 sample->draw_rectangle (0, 0, sample->get_w (), sample->get_h ());
300 void ChromaKeyWindow::done_event(int result)
302 color_thread->close_window();
306 ChromaKeyColor::ChromaKeyColor (ChromaKeyHSV * plugin,
307 ChromaKeyWindow * gui, int x, int y):
308 BC_GenericButton (x, y, _("Color..."))
310 this->plugin = plugin;
315 ChromaKeyColor::handle_event ()
317 gui->color_thread->start_window (plugin->config.get_color (), 0xff);
324 ChromaKeyMinBrightness::ChromaKeyMinBrightness (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
327 xS(200), yS(200), (float) 0, (float) 100, plugin->config.min_brightness)
329 this->plugin = plugin;
330 set_precision (0.01);
334 ChromaKeyMinBrightness::handle_event ()
336 plugin->config.min_brightness = get_value ();
337 plugin->send_configure_change ();
341 ChromaKeyMaxBrightness::ChromaKeyMaxBrightness (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
344 xS(200), yS(200), (float) 0, (float) 100, plugin->config.max_brightness)
346 this->plugin = plugin;
347 set_precision (0.01);
351 ChromaKeyMaxBrightness::handle_event ()
353 plugin->config.max_brightness = get_value ();
354 plugin->send_configure_change ();
359 ChromaKeySaturation::ChromaKeySaturation (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
361 0, xS(200), yS(200), (float) 0, (float) 100, plugin->config.saturation)
363 this->plugin = plugin;
364 set_precision (0.01);
368 ChromaKeySaturation::handle_event ()
370 plugin->config.saturation = get_value ();
371 plugin->send_configure_change ();
375 ChromaKeyMinSaturation::ChromaKeyMinSaturation (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
378 xS(200), yS(200), (float) 0, (float) 100, plugin->config.min_saturation)
380 this->plugin = plugin;
381 set_precision (0.01);
385 ChromaKeyMinSaturation::handle_event ()
387 plugin->config.min_saturation = get_value ();
388 plugin->send_configure_change ();
393 ChromaKeyTolerance::ChromaKeyTolerance (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
395 0, xS(200), yS(200), (float) 0, (float) 100, plugin->config.tolerance)
397 this->plugin = plugin;
398 set_precision (0.01);
402 ChromaKeyTolerance::handle_event ()
404 plugin->config.tolerance = get_value ();
405 plugin->send_configure_change ();
411 ChromaKeyInSlope::ChromaKeyInSlope (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
413 0, xS(200), yS(200), (float) 0, (float) 20, plugin->config.in_slope)
415 this->plugin = plugin;
416 set_precision (0.01);
420 ChromaKeyInSlope::handle_event ()
422 plugin->config.in_slope = get_value ();
423 plugin->send_configure_change ();
428 ChromaKeyOutSlope::ChromaKeyOutSlope (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
430 0, xS(200), yS(200), (float) 0, (float) 20, plugin->config.out_slope)
432 this->plugin = plugin;
433 set_precision (0.01);
437 ChromaKeyOutSlope::handle_event ()
439 plugin->config.out_slope = get_value ();
440 plugin->send_configure_change ();
445 ChromaKeyAlphaOffset::ChromaKeyAlphaOffset (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
448 xS(200), yS(200), (float) -100, (float) 100, plugin->config.alpha_offset)
450 this->plugin = plugin;
451 set_precision (0.01);
455 ChromaKeyAlphaOffset::handle_event ()
457 plugin->config.alpha_offset = get_value ();
458 plugin->send_configure_change ();
462 ChromaKeyShowMask::ChromaKeyShowMask (ChromaKeyHSV * plugin, int x, int y):BC_CheckBox (x, y, plugin->config.show_mask,
466 this->plugin = plugin;
471 ChromaKeyShowMask::handle_event ()
473 plugin->config.show_mask = get_value ();
474 plugin->send_configure_change ();
478 ChromaKeyReset::ChromaKeyReset (ChromaKeyHSV *plugin, ChromaKeyWindow *gui, int x, int y)
479 :BC_GenericButton(x, y, _("Reset"))
481 this->plugin = plugin;
485 int ChromaKeyReset::handle_event ()
487 plugin->config.reset();
489 plugin->send_configure_change();
493 ChromaKeyUseColorPicker::ChromaKeyUseColorPicker (ChromaKeyHSV * plugin, ChromaKeyWindow * gui, int x, int y)
494 : BC_GenericButton (x, y,
496 ("Use color picker"))
498 this->plugin = plugin;
503 ChromaKeyUseColorPicker::handle_event ()
505 plugin->config.red = plugin->get_red ();
506 plugin->config.green = plugin->get_green ();
507 plugin->config.blue = plugin->get_blue ();
509 gui->update_sample ();
512 plugin->send_configure_change ();
518 ChromaKeySpillThreshold::ChromaKeySpillThreshold (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
521 xS(200), yS(200), (float) 0, (float) 100, plugin->config.spill_threshold)
523 this->plugin = plugin;
524 set_precision (0.01);
528 ChromaKeySpillThreshold::handle_event ()
530 plugin->config.spill_threshold = get_value ();
531 plugin->send_configure_change ();
535 ChromaKeySpillAmount::ChromaKeySpillAmount (ChromaKeyHSV * plugin, int x, int y):BC_FSlider (x,
537 0, xS(200), yS(200), (float) 0, (float) 100, plugin->config.spill_amount)
539 this->plugin = plugin;
540 set_precision (0.01);
544 ChromaKeySpillAmount::handle_event ()
546 plugin->config.spill_amount = get_value ();
547 plugin->send_configure_change ();
556 ChromaKeyColorThread::ChromaKeyColorThread (ChromaKeyHSV * plugin, ChromaKeyWindow * gui)
557 : ColorPicker (1, _("Inner color"))
559 this->plugin = plugin;
564 ChromaKeyColorThread::handle_new_color (int output, int alpha)
566 plugin->config.red = (float) (output & 0xff0000) / 0xff0000;
567 plugin->config.green = (float) (output & 0xff00) / 0xff00;
568 plugin->config.blue = (float) (output & 0xff) / 0xff;
570 get_gui()->unlock_window();
571 gui->lock_window("ChromaKeyColorThread::handle_new_color");
572 gui->update_sample ();
573 gui->unlock_window();
574 get_gui()->lock_window("ChromaKeyColorThread::handle_new_color");
577 plugin->send_configure_change ();
588 ChromaKeyServer::ChromaKeyServer (ChromaKeyHSV * plugin):LoadServer (plugin->PluginClient::smp + 1,
589 plugin->PluginClient::smp +
592 this->plugin = plugin;
596 ChromaKeyServer::init_packages ()
598 for (int i = 0; i < get_total_packages (); i++)
600 ChromaKeyPackage *pkg = (ChromaKeyPackage *) get_package (i);
601 pkg->y1 = plugin->input->get_h () * i / get_total_packages ();
602 pkg->y2 = plugin->input->get_h () * (i + 1) / get_total_packages ();
607 ChromaKeyServer::new_client ()
609 return new ChromaKeyUnit (plugin, this);
613 ChromaKeyServer::new_package ()
615 return new ChromaKeyPackage;
620 ChromaKeyPackage::ChromaKeyPackage ():LoadPackage ()
624 ChromaKeyUnit::ChromaKeyUnit (ChromaKeyHSV * plugin, ChromaKeyServer * server):LoadClient
627 this->plugin = plugin;
633 #define ABS(a) ((a<0)?-(a):a)
634 // Reuse as much as possible in the opengl version
635 #define OUTER_VARIABLES \
636 float red = plugin->config.red; \
637 float green = plugin->config.green; \
638 float blue = plugin->config.blue; \
640 float in_slope = plugin->config.in_slope / 100; \
641 float out_slope = plugin->config.out_slope / 100; \
643 float tolerance = plugin->config.tolerance / 100; \
644 float tolerance_in = tolerance - in_slope; \
645 float tolerance_out = tolerance + out_slope; \
647 float sat = plugin->config.saturation / 100; \
648 float min_s = plugin->config.min_saturation / 100; \
649 float min_s_in = min_s + in_slope; \
650 float min_s_out = min_s - out_slope; \
652 float min_v = plugin->config.min_brightness / 100; \
653 float min_v_in = min_v + in_slope; \
654 float min_v_out = min_v - out_slope; \
656 float max_v = plugin->config.max_brightness / 100; \
657 float max_v_in = max_v - in_slope; \
658 float max_v_out = max_v + out_slope; \
660 float spill_threshold = plugin->config.spill_threshold / 100; \
661 float spill_amount = 1.0 - plugin->config.spill_amount / 100; \
663 float alpha_offset = plugin->config.alpha_offset / 100; \
665 /* Convert RGB key to HSV key */ \
666 float hue_key, saturation_key, value_key; \
667 HSV::rgb_to_hsv(red, \
675 template <typename component_type>
676 void ChromaKeyUnit::process_chromakey(int components,
679 ChromaKeyPackage *pkg)
683 int w = plugin->input->get_w();
685 for (int i = pkg->y1; i < pkg->y2; i++)
687 component_type *row = (component_type *) plugin->input->get_rows ()[i];
689 for (int j = 0; j < w; j++)
691 float r, g, b, a = 1;
693 r = (float) row[0] / max;
694 g = (float) row[1] / max;
695 b = (float) row[2] / max;
698 YUV::yuv.yuv_to_rgb_f (r, g, b, row[0], row[1], row[2]);
702 float av = 1, ah = 1, as = 1, avm = 1;
703 bool has_match = true;
705 HSV::rgb_to_hsv (r, g, b, h, s, v);
707 // First, test if the hue is in range
710 if(h <= hue_key - tolerance_in * 180.0)
713 if(h >= hue_key + tolerance_in * 180.0)
720 if (ABS (h - hue_key) < tolerance_in * 180)
723 if ((out_slope != 0) && (ABS (h - hue_key) < tolerance * 180))
724 /* we scale alpha between 0 and 1/2 */
725 ah = ABS (h - hue_key) / tolerance / 360;
727 if (ABS (h - hue_key) < tolerance_out * 180)
728 /* we scale alpha between 1/2 and 1 */
729 ah = ABS (h - hue_key) / tolerance_out / 360;
733 // Check if the saturation matches
738 else if (s - sat >= min_s_in)
740 else if ((out_slope != 0) && (s - sat > min_s))
741 as = (s - sat - min_s) / (min_s * 2);
742 else if (s - sat > min_s_out)
743 as = (s - sat - min_s_out) / (min_s_out * 2);
748 // Check if the value is more than the minimun
753 else if (v >= min_v_in)
755 else if ((out_slope != 0) && (v > min_v))
756 av = (v - min_v) / (min_v * 2);
757 else if (v > min_v_out)
758 av = (v - min_v_out) / (min_v_out * 2);
763 // Check if the value is less than the maximum
768 else if (v <= max_v_in)
770 else if ((out_slope != 0) && (v < max_v))
771 avm = (v - max_v) / (max_v * 2);
772 else if (v < max_v_out)
773 avm = (v - max_v_out) / (max_v_out * 2);
778 // If the color is part of the key, update the alpha channel
780 a = MAX (MAX (ah, av), MAX (as, avm));
782 // Spill light processing
783 if ((ABS (h - hue_key) < spill_threshold * 180) ||
784 ((ABS (h - hue_key) > 360)
785 && (ABS (h - hue_key) - 360 < spill_threshold * 180)))
787 s = s * spill_amount * ABS (h - hue_key) / (spill_threshold * 180);
789 HSV::hsv_to_rgb (r, g, b, h, s, v);
792 row[0] = (component_type) ((float) r * max);
793 row[1] = (component_type) ((float) g * max);
794 row[2] = (component_type) ((float) b * max);
797 YUV::yuv.rgb_to_yuv_f(r, g, b, row[0], row[1], row[2]);
803 if (plugin->config.show_mask)
808 row[0] = (component_type) ((float) a * max);
809 row[1] = (component_type) ((float) max / 2);
810 row[2] = (component_type) ((float) max / 2);
814 row[0] = (component_type) ((float) a * max);
815 row[1] = (component_type) ((float) a * max);
816 row[2] = (component_type) ((float) a * max);
820 /* Multiply alpha and put back in frame */
823 row[3] = MIN ((component_type) (a * max), row[3]);
827 row[0] = (component_type) ((float) a * row[0]);
829 (component_type) ((float) a * (row[1] - (max / 2 + 1)) +
832 (component_type) ((float) a * (row[2] - (max / 2 + 1)) +
837 row[0] = (component_type) ((float) a * row[0]);
838 row[1] = (component_type) ((float) a * row[1]);
839 row[2] = (component_type) ((float) a * row[2]);
850 void ChromaKeyUnit::process_package(LoadPackage *package)
852 ChromaKeyPackage *pkg = (ChromaKeyPackage*)package;
855 switch(plugin->input->get_color_model())
858 process_chromakey<float> (3, 1.0, 0, pkg);
861 process_chromakey<float> ( 4, 1.0, 0, pkg);
864 process_chromakey<unsigned char> ( 3, 0xff, 0, pkg);
867 process_chromakey<unsigned char> ( 4, 0xff, 0, pkg);
870 process_chromakey<unsigned char> ( 3, 0xff, 1, pkg);
873 process_chromakey<unsigned char> ( 4, 0xff, 1, pkg);
876 process_chromakey<uint16_t> (3, 0xffff, 1, pkg);
878 case BC_YUVA16161616:
879 process_chromakey<uint16_t> (4, 0xffff, 1, pkg);
889 REGISTER_PLUGIN(ChromaKeyHSV)
893 ChromaKeyHSV::ChromaKeyHSV(PluginServer *server)
894 : PluginVClient(server)
900 ChromaKeyHSV::~ChromaKeyHSV()
903 if(engine) delete engine;
907 int ChromaKeyHSV::process_buffer(VFrame *frame,
908 int64_t start_position,
911 load_configuration();
913 this->output = frame;
921 if(get_use_opengl()) return run_opengl();
924 if(!engine) engine = new ChromaKeyServer(this);
925 engine->process_packages();
930 const char* ChromaKeyHSV::plugin_title() { return N_("Chroma key (HSV)"); }
931 int ChromaKeyHSV::is_realtime() { return 1; }
934 LOAD_CONFIGURATION_MACRO(ChromaKeyHSV, ChromaKeyConfig)
937 void ChromaKeyHSV::save_data(KeyFrame * keyframe)
940 output.set_shared_output(keyframe->xbuf);
941 output.tag.set_title("CHROMAKEY_HSV");
942 output.tag.set_property("RED", config.red);
943 output.tag.set_property("GREEN", config.green);
944 output.tag.set_property("BLUE", config.blue);
945 output.tag.set_property("MIN_BRIGHTNESS", config.min_brightness);
946 output.tag.set_property("MAX_BRIGHTNESS", config.max_brightness);
947 output.tag.set_property("SATURATION", config.saturation);
948 output.tag.set_property("MIN_SATURATION", config.min_saturation);
949 output.tag.set_property("TOLERANCE", config.tolerance);
950 output.tag.set_property("IN_SLOPE", config.in_slope);
951 output.tag.set_property("OUT_SLOPE", config.out_slope);
952 output.tag.set_property("ALPHA_OFFSET", config.alpha_offset);
953 output.tag.set_property("SPILL_THRESHOLD", config.spill_threshold);
954 output.tag.set_property("SPILL_AMOUNT", config.spill_amount);
955 output.tag.set_property("SHOW_MASK", config.show_mask);
957 output.tag.set_title("/CHROMAKEY_HSV");
959 output.append_newline();
960 output.terminate_string();
963 void ChromaKeyHSV::read_data(KeyFrame * keyframe)
967 input.set_shared_input(keyframe->xbuf);
969 while( !input.read_tag() ) {
970 if( input.tag.title_is("CHROMAKEY_HSV") ) {
971 config.red = input.tag.get_property("RED", config.red);
972 config.green = input.tag.get_property("GREEN", config.green);
973 config.blue = input.tag.get_property("BLUE", config.blue);
974 config.min_brightness =
975 input.tag.get_property("MIN_BRIGHTNESS", config.min_brightness);
976 config.max_brightness =
977 input.tag.get_property("MAX_BRIGHTNESS", config.max_brightness);
979 input.tag.get_property("SATURATION", config.saturation);
980 config.min_saturation =
981 input.tag.get_property("MIN_SATURATION", config.min_saturation);
983 input.tag.get_property("TOLERANCE", config.tolerance);
985 input.tag.get_property("IN_SLOPE", config.in_slope);
987 input.tag.get_property("OUT_SLOPE", config.out_slope);
988 config.alpha_offset =
989 input.tag.get_property("ALPHA_OFFSET", config.alpha_offset);
990 config.spill_threshold =
991 input.tag.get_property("SPILL_THRESHOLD",
992 config.spill_threshold);
993 config.spill_amount =
994 input.tag.get_property("SPILL_AMOUNT", config.spill_amount);
996 input.tag.get_property("SHOW_MASK", config.show_mask);
1002 NEW_WINDOW_MACRO(ChromaKeyHSV, ChromaKeyWindow)
1004 void ChromaKeyHSV::update_gui()
1007 load_configuration();
1008 ChromaKeyWindow *window = (ChromaKeyWindow*)thread->window;
1009 window->lock_window();
1010 window->update_gui();
1011 window->unlock_window();
1015 void ChromaKeyWindow::update_gui()
1017 ChromaKeyConfig &config = plugin->config;
1018 min_brightness->update(config.min_brightness);
1019 max_brightness->update(config.max_brightness);
1020 saturation->update(config.saturation);
1021 min_saturation->update(config.min_saturation);
1022 tolerance->update(config.tolerance);
1023 in_slope->update(config.in_slope);
1024 out_slope->update(config.out_slope);
1025 alpha_offset->update(config.alpha_offset);
1026 spill_threshold->update(config.spill_threshold);
1027 spill_amount->update(config.spill_amount);
1028 show_mask->update(config.show_mask);
1034 int ChromaKeyHSV::handle_opengl()
1038 ChromaKeyHSV *plugin = this;
1041 static const char *yuv_shader =
1042 "const vec3 black = vec3(0.0, 0.5, 0.5);\n"
1043 "uniform mat3 yuv_to_rgb_matrix;\n"
1044 "uniform mat3 rgb_to_yuv_matrix;\n"
1045 "uniform float yminf;\n"
1047 "vec4 yuv_to_rgb(vec4 color)\n"
1049 " color.rgb -= vec3(yminf, 0.5, 0.5);\n"
1050 " color.rgb = yuv_to_rgb_matrix * color.rgb;\n"
1054 "vec4 rgb_to_yuv(vec4 color)\n"
1056 " color.rgb = rgb_to_yuv_matrix * color.rgb;\n"
1057 " color.rgb += vec3(yminf, 0.5, 0.5);\n"
1061 static const char *rgb_shader =
1062 "const vec3 black = vec3(0.0, 0.0, 0.0);\n"
1064 "vec4 yuv_to_rgb(vec4 color)\n"
1068 "vec4 rgb_to_yuv(vec4 color)\n"
1073 static const char *hsv_shader =
1074 "vec4 rgb_to_hsv(vec4 color)\n"
1076 RGB_TO_HSV_FRAG("color")
1080 "vec4 hsv_to_rgb(vec4 color)\n"
1082 HSV_TO_RGB_FRAG("color")
1087 static const char *show_rgbmask_shader =
1088 "vec4 show_mask(vec4 color, vec4 color2)\n"
1090 " return vec4(1.0, 1.0, 1.0, min(color.a, color2.a));"
1093 static const char *show_yuvmask_shader =
1094 "vec4 show_mask(vec4 color, vec4 color2)\n"
1096 " return vec4(1.0, 0.5, 0.5, min(color.a, color2.a));"
1099 static const char *nomask_shader =
1100 "vec4 show_mask(vec4 color, vec4 color2)\n"
1102 " return vec4(color.rgb, min(color.a, color2.a));"
1105 get_output()->to_texture();
1106 get_output()->enable_opengl();
1107 get_output()->init_screen();
1109 const char *shader_stack[16];
1110 memset(shader_stack,0, sizeof(shader_stack));
1111 int current_shader = 0;
1113 shader_stack[current_shader++] = \
1114 !BC_CModels::is_yuv(get_output()->get_color_model()) ?
1115 rgb_shader : yuv_shader;
1116 shader_stack[current_shader++] = hsv_shader;
1117 shader_stack[current_shader++] = !config.show_mask ? nomask_shader :
1118 !BC_CModels::is_yuv(get_output()->get_color_model()) ?
1119 show_rgbmask_shader : show_yuvmask_shader ;
1120 extern unsigned char _binary_chromakey_sl_start[];
1121 static const char *shader_frag = (char*)_binary_chromakey_sl_start;
1122 shader_stack[current_shader++] = shader_frag;
1124 shader_stack[current_shader] = 0;
1125 unsigned int shader = VFrame::make_shader(shader_stack);
1127 glUseProgram(shader);
1128 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
1129 glUniform1f(glGetUniformLocation(shader, "red"), red);
1130 glUniform1f(glGetUniformLocation(shader, "green"), green);
1131 glUniform1f(glGetUniformLocation(shader, "blue"), blue);
1132 glUniform1f(glGetUniformLocation(shader, "in_slope"), in_slope);
1133 glUniform1f(glGetUniformLocation(shader, "out_slope"), out_slope);
1134 glUniform1f(glGetUniformLocation(shader, "tolerance"), tolerance);
1135 glUniform1f(glGetUniformLocation(shader, "tolerance_in"), tolerance_in);
1136 glUniform1f(glGetUniformLocation(shader, "tolerance_out"), tolerance_out);
1137 glUniform1f(glGetUniformLocation(shader, "sat"), sat);
1138 glUniform1f(glGetUniformLocation(shader, "min_s"), min_s);
1139 glUniform1f(glGetUniformLocation(shader, "min_s_in"), min_s_in);
1140 glUniform1f(glGetUniformLocation(shader, "min_s_out"), min_s_out);
1141 glUniform1f(glGetUniformLocation(shader, "min_v"), min_v);
1142 glUniform1f(glGetUniformLocation(shader, "min_v_in"), min_v_in);
1143 glUniform1f(glGetUniformLocation(shader, "min_v_out"), min_v_out);
1144 glUniform1f(glGetUniformLocation(shader, "max_v"), max_v);
1145 glUniform1f(glGetUniformLocation(shader, "max_v_in"), max_v_in);
1146 glUniform1f(glGetUniformLocation(shader, "max_v_out"), max_v_out);
1147 glUniform1f(glGetUniformLocation(shader, "spill_threshold"), spill_threshold);
1148 glUniform1f(glGetUniformLocation(shader, "spill_amount"), spill_amount);
1149 glUniform1f(glGetUniformLocation(shader, "alpha_offset"), alpha_offset);
1150 glUniform1f(glGetUniformLocation(shader, "hue_key"), hue_key);
1151 glUniform1f(glGetUniformLocation(shader, "saturation_key"), saturation_key);
1152 glUniform1f(glGetUniformLocation(shader, "value_key"), value_key);
1153 if( BC_CModels::is_yuv(get_output()->get_color_model()) )
1154 BC_GL_COLORS(shader);
1157 get_output()->bind_texture(0);
1158 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1159 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1161 if(BC_CModels::components(get_output()->get_color_model()) == 3)
1164 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1165 get_output()->clear_pbuffer();
1167 get_output()->draw_texture();
1170 get_output()->set_opengl_state(VFrame::SCREEN);
1171 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1172 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1173 glDisable(GL_BLEND);