3 * Copyright (C) 2012-2024 Adam Williams <broadcast at earthling dot net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 // original chromakey HSV author:
23 // http://jcornet.free.fr/linux/chromakey.html
25 // He was trying to replicate the Avid SpectraMatte:
26 // https://resources.avid.com/SupportFiles/attach/Symphony_Effects_and_CC_Guide_v5.5.pdf
28 // but the problem seems to be harder than he thought
30 // A rewrite got a slightly different spill light processing
31 // but still not very useful:
32 // https://github.com/vanakala/cinelerra-cve/blob/master/plugins/chromakeyhsv/chromakey.C
34 // The current implementation is most of the Spectramatte algorithm.
35 // The only way to test it is to use the color swatch plugin.
36 // Fix brightness to test the saturation wedge.
37 // Fix saturation to test the brightness wedge.
39 // There are boundary artifacts caused by the color swatch showing a slice
41 // If out slope > 0, constant 0% saturation or 0% brightness is all wedge.
42 // If out slope == 0, constant 0% saturation or constant 0% brightness has no wedge
43 // The general idea is if it's acting weird, switch between constant brightness
44 // & constant saturation.
46 // TODO: integrated color swatch & alpha blur, but it takes a lot of space in the GUI.
48 #include "bcdisplayinfo.h"
49 #include "bcsignals.h"
50 #include "chromakey.h"
57 #include "loadbalance.h"
58 #include "playback3d.h"
60 #include "pluginvclient.h"
67 #define WINDOW_W xS(550)
68 #define WINDOW_H yS(600)
69 #define SLIDER_W xS(250)
70 #define MAX_SLOPE 100.0
71 #define MAX_VALUE 100.0
73 ChromaKeyConfig::ChromaKeyConfig ()
79 min_brightness = 50.0;
80 max_brightness = 100.0;
82 saturation_start = 0.0;
83 saturation_line = 50.0;
89 spill_saturation = 0.0;
98 undo_min_brightness = min_brightness;
99 undo_max_brightness = max_brightness;
100 undo_tolerance = tolerance;
101 undo_saturation_start = saturation_start;
102 undo_saturation_line = saturation_line;
103 undo_in_slope = in_slope;
104 undo_out_slope = out_slope;
105 undo_alpha_offset = alpha_offset;
106 undo_spill_saturation = spill_saturation;
107 undo_spill_angle = spill_angle;
108 undo_desaturate_only = desaturate_only;
109 undo_show_mask = show_mask;
114 store_min_brightness = min_brightness;
115 store_max_brightness = max_brightness;
116 store_tolerance = tolerance;
117 store_saturation_start = saturation_start;
118 store_saturation_line = saturation_line;
119 store_in_slope = in_slope;
120 store_out_slope = out_slope;
121 store_alpha_offset = alpha_offset;
122 store_spill_saturation = spill_saturation;
123 store_spill_angle = spill_angle;
124 store_desaturate_only = desaturate_only;
125 store_show_mask = show_mask;
128 void ChromaKeyConfig::reset(int clear)
137 case RESET_MIN_BRIGHTNESS:
138 min_brightness = 50.0;
140 case RESET_MAX_BRIGHTNESS:
141 max_brightness = 100.0;
143 case RESET_TOLERANCE:
146 case RESET_SATURATION_START:
147 saturation_start = 0.0;
149 case RESET_SATURATION_LINE:
150 saturation_line = 50.0;
155 case RESET_OUT_SLOPE:
158 case RESET_ALPHA_OFFSET:
161 case RESET_SPILL_SATURATION:
162 spill_saturation = 0.0;
164 case RESET_SPILL_ANGLE:
168 case RESET_DEFAULT_SETTINGS:
173 undo_min_brightness = min_brightness;
174 undo_max_brightness = max_brightness;
175 undo_tolerance = tolerance;
176 undo_saturation_start = saturation_start;
177 undo_saturation_line = saturation_line;
178 undo_in_slope = in_slope;
179 undo_out_slope = out_slope;
180 undo_alpha_offset = alpha_offset;
181 undo_spill_saturation = spill_saturation;
182 undo_spill_angle = spill_angle;
183 undo_desaturate_only = desaturate_only;
184 undo_show_mask = show_mask;
190 min_brightness = 50.0;
191 max_brightness = 100.0;
193 saturation_start = 0.0;
194 saturation_line = 50.0;
200 spill_saturation = 0.0;
211 ChromaKeyConfig::copy_from (ChromaKeyConfig & src)
216 spill_saturation = src.spill_saturation;
217 spill_angle = src.spill_angle;
218 min_brightness = src.min_brightness;
219 max_brightness = src.max_brightness;
220 saturation_start = src.saturation_start;
221 saturation_line = src.saturation_line;
222 tolerance = src.tolerance;
223 in_slope = src.in_slope;
224 out_slope = src.out_slope;
225 alpha_offset = src.alpha_offset;
226 show_mask = src.show_mask;
227 desaturate_only = src.desaturate_only;
230 undo_green = src.green;
231 undo_blue = src.blue;
232 undo_min_brightness = src.min_brightness;
233 undo_max_brightness = src.max_brightness;
234 undo_tolerance = src.tolerance;
235 undo_saturation_start = src.saturation_start;
236 undo_saturation_line = src.saturation_line;
237 undo_in_slope = src.in_slope;
238 undo_out_slope = src.out_slope;
239 undo_alpha_offset = src.alpha_offset;
240 undo_spill_saturation = src.spill_saturation;
241 undo_spill_angle = src.spill_angle;
242 undo_desaturate_only = src.desaturate_only;
243 undo_show_mask = src.show_mask;
247 ChromaKeyConfig::equivalent (ChromaKeyConfig & src)
249 return (EQUIV (red, src.red) &&
250 EQUIV (green, src.green) &&
251 EQUIV (blue, src.blue) &&
252 EQUIV (spill_saturation, src.spill_saturation) &&
253 EQUIV (spill_angle, src.spill_angle) &&
254 EQUIV (min_brightness, src.min_brightness) &&
255 EQUIV (max_brightness, src.max_brightness) &&
256 EQUIV (saturation_start, src.saturation_start) &&
257 EQUIV (saturation_line, src.saturation_line) &&
258 EQUIV (tolerance, src.tolerance) &&
259 EQUIV (in_slope, src.in_slope) &&
260 EQUIV (out_slope, src.out_slope) &&
261 EQUIV (alpha_offset, src.alpha_offset) &&
262 show_mask == src.show_mask &&
263 desaturate_only == src.desaturate_only);
267 ChromaKeyConfig::interpolate (ChromaKeyConfig & prev,
268 ChromaKeyConfig & next,
271 int64_t current_frame)
274 (double) (current_frame - prev_frame) / (next_frame - prev_frame);
276 (double) (next_frame - current_frame) / (next_frame - prev_frame);
278 this->red = prev.red * prev_scale + next.red * next_scale;
279 this->green = prev.green * prev_scale + next.green * next_scale;
280 this->blue = prev.blue * prev_scale + next.blue * next_scale;
281 this->spill_saturation =
282 prev.spill_saturation * prev_scale + next.spill_saturation * next_scale;
284 prev.spill_angle * prev_scale + next.tolerance * next_scale;
285 this->min_brightness =
286 prev.min_brightness * prev_scale + next.min_brightness * next_scale;
287 this->max_brightness =
288 prev.max_brightness * prev_scale + next.max_brightness * next_scale;
289 this->saturation_start =
290 prev.saturation_start * prev_scale + next.saturation_start * next_scale;
291 this->saturation_line =
292 prev.saturation_line * prev_scale + next.saturation_line * next_scale;
293 this->tolerance = prev.tolerance * prev_scale + next.tolerance * next_scale;
294 this->in_slope = prev.in_slope * prev_scale + next.in_slope * next_scale;
295 this->out_slope = prev.out_slope * prev_scale + next.out_slope * next_scale;
297 prev.alpha_offset * prev_scale + next.alpha_offset * next_scale;
298 this->show_mask = prev.show_mask;
299 this->desaturate_only = prev.desaturate_only;
301 this->undo_red = this->red;
302 this->undo_green = this->green;
303 this->undo_blue = this->blue;
304 this->undo_min_brightness = this->min_brightness;
305 this->undo_max_brightness = this->max_brightness;
306 this->undo_tolerance = this->tolerance;
307 this->undo_saturation_start = this->saturation_start;
308 this->undo_saturation_line = this->saturation_line;
309 this->undo_in_slope = this->in_slope;
310 this->undo_out_slope = this->out_slope;
311 this->undo_alpha_offset = this->alpha_offset;
312 this->undo_spill_saturation = this->spill_saturation;
313 this->undo_spill_angle = this->spill_angle;
314 this->undo_desaturate_only = this->desaturate_only;
315 this->undo_show_mask = this->show_mask;
319 ChromaKeyConfig::get_color ()
321 int red = (int) (CLIP (this->red, 0, 1) * 0xff);
322 int green = (int) (CLIP (this->green, 0, 1) * 0xff);
323 int blue = (int) (CLIP (this->blue, 0, 1) * 0xff);
324 return (red << 16) | (green << 8) | blue;
329 ChromaKeyWindow::ChromaKeyWindow (ChromaKeyAvid * plugin)
330 : PluginClientWindow(plugin,
337 this->plugin = plugin;
341 ChromaKeyWindow::~ChromaKeyWindow ()
346 void ChromaKeyWindow::create_objects ()
348 int xs10 = xS(10), xs20 = xS(20), xs100 = xS(100), wslid = SLIDER_W;
349 int ys10 = yS(10), ys20 = yS(20), ys30 = yS(30), ys40 = yS(40), ys50 = yS(50);
350 int y = ys10, x2 = xS(160), x3 = xS(260), xs5 = xS(5);
352 int clr_x = get_w()-x - xS(22); // note: clrBtn_w = 22
356 BC_TitleBar *title_bar;
359 add_subwindow (title_bar =
360 new BC_TitleBar(x, y, get_w()-2*x, xs20, xs10, _("Color")));
363 add_subwindow (color = new ChromaKeyColor (plugin, this, x, y));
364 // Info for Sample rectangle: x_slider w_slider w_sample
366 add_subwindow (sample = new BC_SubWindow (x3 + wslid - xs100, y, xs100, ys50));
368 add_subwindow (use_colorpicker = new ChromaKeyUseColorPicker (plugin, this, x, y));
370 add_subwindow (show_mask =
371 new ChromaKeyToggle (plugin, x, y, &plugin->config.show_mask,
374 // Key parameters section
376 add_subwindow (title_bar =
377 new BC_TitleBar (x, y, get_w()-2*x, xs20, xs10,
378 _("Key parameters")));
380 add_subwindow (title = new BC_Title (x, y, _("Hue Tolerance:")));
381 tolerance_text = new ChromaKeyText (plugin, this, 0, x+x2, y, 0, MAX_VALUE,
382 &plugin->config.tolerance);
383 tolerance_text->create_objects();
384 tolerance = new ChromaKeySlider (plugin, tolerance_text, x3, y, wslid,
385 0, MAX_VALUE, &plugin->config.tolerance);
386 add_subwindow (tolerance);
387 tolerance_text->slider = tolerance;
388 clr_x = x3 + tolerance->get_w() + x;
389 add_subwindow (tolerance_clr =
390 new ChromaKeyClr (plugin, this, clr_x, y, RESET_TOLERANCE));
393 add_subwindow (title = new BC_Title (x, y, _("Min. Brightness:")));
394 min_brightness_text = new ChromaKeyText (plugin, this, 0, x+x2, y,
396 &plugin->config.min_brightness);
397 min_brightness_text->create_objects();
398 min_brightness = new ChromaKeySlider (plugin, min_brightness_text,
399 x3, y, wslid, 0, MAX_VALUE,
400 &plugin->config.min_brightness);
401 add_subwindow(min_brightness);
402 min_brightness_text->slider = min_brightness;
403 add_subwindow (min_brightness_clr =
404 new ChromaKeyClr (plugin, this, clr_x, y,
405 RESET_MIN_BRIGHTNESS));
408 add_subwindow (title = new BC_Title (x, y, _("Max. Brightness:")));
409 max_brightness_text = new ChromaKeyText (plugin, this, 0, x+x2, y,
411 &plugin->config.max_brightness);
412 max_brightness_text->create_objects();
413 max_brightness = new ChromaKeySlider (plugin, max_brightness_text,
414 x3, y, wslid, 0, MAX_VALUE,
415 &plugin->config.max_brightness);
416 add_subwindow(max_brightness);
417 max_brightness_text->slider = max_brightness;
418 add_subwindow (max_brightness_clr =
419 new ChromaKeyClr (plugin, this, clr_x, y,
420 RESET_MAX_BRIGHTNESS));
423 add_subwindow (title = new BC_Title (x, y, _("Saturation Start:")));
424 saturation_start_text = new ChromaKeyText (plugin, this, 0, x+x2, y,
426 &plugin->config.saturation_start);
427 saturation_start_text->create_objects();
428 saturation_start = new ChromaKeySlider (plugin, saturation_start_text,
429 x3, y, wslid, 0, MAX_VALUE,
430 &plugin->config.saturation_start);
431 add_subwindow(saturation_start);
432 saturation_start_text->slider = saturation_start;
433 add_subwindow (saturation_start_clr =
434 new ChromaKeyClr (plugin, this, clr_x, y,
435 RESET_SATURATION_START));
438 add_subwindow (title = new BC_Title (x, y, _("Saturation Line:")));
439 saturation_line_text = new ChromaKeyText (plugin, this, 0, x+x2, y,
441 &plugin->config.saturation_line);
442 saturation_line_text->create_objects();
443 saturation_line = new ChromaKeySlider (plugin, saturation_line_text,
444 x3, y, wslid, 0, MAX_VALUE,
445 &plugin->config.saturation_line);
446 add_subwindow(saturation_line);
447 saturation_line_text->slider = saturation_line;
448 add_subwindow (saturation_line_clr =
449 new ChromaKeyClr (plugin, this, clr_x, y,
450 RESET_SATURATION_LINE));
453 // Mask tweaking section
454 add_subwindow (title_bar =
455 new BC_TitleBar (x, y, get_w()-2*x, xs20, xs10,
456 _("Mask tweaking")));
458 add_subwindow (title = new BC_Title (x, y, _("In Slope:")));
459 in_slope_text = new ChromaKeyText (plugin, this, 0, x+x2, y, 0, MAX_SLOPE,
460 &plugin->config.in_slope);
461 in_slope_text->create_objects();
462 in_slope = new ChromaKeySlider (plugin, in_slope_text, x3, y, wslid,
463 0, MAX_SLOPE, &plugin->config.in_slope);
464 add_subwindow(in_slope);
465 in_slope_text->slider = in_slope;
466 add_subwindow (in_slope_clr =
467 new ChromaKeyClr (plugin, this, clr_x, y, RESET_IN_SLOPE));
470 add_subwindow (title = new BC_Title (x, y, _("Out Slope:")));
471 out_slope_text = new ChromaKeyText (plugin, this, 0, x+x2, y, 0, MAX_SLOPE,
472 &plugin->config.out_slope);
473 out_slope_text->create_objects();
474 out_slope = new ChromaKeySlider (plugin, out_slope_text, x3, y, wslid,
475 0, MAX_SLOPE, &plugin->config.out_slope);
476 add_subwindow(out_slope);
477 out_slope_text->slider = out_slope;
478 add_subwindow (out_slope_clr =
479 new ChromaKeyClr (plugin, this, clr_x, y, RESET_OUT_SLOPE));
482 add_subwindow (title = new BC_Title (x, y, _("Alpha Offset:")));
483 alpha_offset_text = new ChromaKeyText (plugin, this, 0, x+x2, y,
484 -MAX_VALUE, MAX_VALUE,
485 &plugin->config.alpha_offset);
486 alpha_offset_text->create_objects();
487 alpha_offset = new ChromaKeySlider (plugin, alpha_offset_text, x3, y, wslid,
488 -MAX_VALUE, MAX_VALUE,
489 &plugin->config.alpha_offset);
490 add_subwindow(alpha_offset);
491 alpha_offset_text->slider = alpha_offset;
492 add_subwindow (alpha_offset_clr =
493 new ChromaKeyClr (plugin, this, clr_x, y, RESET_ALPHA_OFFSET));
496 // Spill light control section
497 add_subwindow (title_bar =
498 new BC_TitleBar (x, y, get_w()-2*x, xs20, xs10,
499 _("Spill light control")));
501 add_subwindow (title = new BC_Title (x, y, _("Spill Saturation:")));
502 spill_saturation_text = new ChromaKeyText (plugin, this, 0, x+x2, y,
504 &plugin->config.spill_saturation);
505 spill_saturation_text->create_objects();
506 spill_saturation = new ChromaKeySlider (plugin, spill_saturation_text,
507 x3, y, wslid, 0, MAX_VALUE,
508 &plugin->config.spill_saturation);
509 add_subwindow(spill_saturation);
510 spill_saturation_text->slider = spill_saturation;
511 add_subwindow (spill_saturation_clr =
512 new ChromaKeyClr (plugin, this, clr_x, y,
513 RESET_SPILL_SATURATION));
516 add_subwindow (title = new BC_Title (x, y, _("Spill Angle:")));
517 spill_angle_text = new ChromaKeyText (plugin, this, 0, x+x2, y, 0, MAX_VALUE,
518 &plugin->config.spill_angle);
519 spill_angle_text->create_objects();
520 spill_angle = new ChromaKeySlider (plugin, spill_angle_text, x3, y, wslid,
521 0, MAX_VALUE, &plugin->config.spill_angle);
522 add_subwindow(spill_angle);
523 spill_angle_text->slider = spill_angle;
524 add_subwindow (spill_angle_clr =
525 new ChromaKeyClr (plugin, this, clr_x, y, RESET_SPILL_ANGLE));
528 add_subwindow(desaturate_only =
529 new ChromaKeyToggle(plugin, x, y,
530 &plugin->config.desaturate_only,
531 _("Desaturate Only")));
534 // Global buttons section
535 add_subwindow (bar = new BC_Bar(x, y, get_w()-2*x));
537 add_subwindow (store = new ChromaKeyStore (plugin, this, x, y));
538 x += store->get_w() + xs5;
539 add_subwindow (recall = new ChromaKeyRecall (plugin, this, x, y));
540 x += recall->get_w() + xs5;
541 add_subwindow (exchange = new ChromaKeyExchange (plugin, this, x, y));
542 x += exchange->get_w() + xs5;
543 add_subwindow (undo = new ChromaKeyUndo (plugin, this, x, y));
544 x += undo->get_w() + xs5;
545 add_subwindow (reset = new ChromaKeyReset (plugin, this, x, y));
547 color_thread = new ChromaKeyColorThread (plugin, this);
554 ChromaKeyWindow::update_sample ()
556 sample->set_color (plugin->config.get_color ());
557 sample->draw_box (0, 0, sample->get_w (), sample->get_h ());
558 sample->set_color (BLACK);
559 sample->draw_rectangle (0, 0, sample->get_w (), sample->get_h ());
563 void ChromaKeyWindow::done_event(int result)
565 color_thread->close_window();
569 ChromaKeyColor::ChromaKeyColor (ChromaKeyAvid * plugin,
570 ChromaKeyWindow * gui, int x, int y)
571 : BC_GenericButton (x, y, _("Color..."))
573 this->plugin = plugin;
578 ChromaKeyColor::handle_event ()
580 gui->color_thread->start_window (plugin->config.get_color (), 0xff);
586 ChromaKeyText::ChromaKeyText(ChromaKeyAvid *plugin, ChromaKeyWindow *gui,
587 ChromaKeySlider *slider, int x, int y,
588 float min, float max, float *output)
589 : BC_TumbleTextBox(gui, *output, min, max, x, y, xS(60), 2)
591 this->plugin = plugin;
593 this->slider = slider;
596 this->output = output;
600 ChromaKeyText::~ChromaKeyText()
604 int ChromaKeyText::handle_event()
606 *output = atof(get_text());
607 if(*output > max) *output = max;
608 if(*output < min) *output = min;
609 slider->update(*output);
610 plugin->send_configure_change();
614 ChromaKeySlider::ChromaKeySlider(ChromaKeyAvid *plugin, ChromaKeyText *text,
616 float min, float max, float *output)
617 : BC_FSlider(x, y, 0, w, w, min, max, *output)
619 this->plugin = plugin;
621 this->output = output;
623 enable_show_value(0); // Hide caption
626 ChromaKeySlider::~ChromaKeySlider()
630 int ChromaKeySlider::handle_event()
632 *output = get_value();
633 text->update(*output);
634 plugin->send_configure_change();
638 ChromaKeyClr::ChromaKeyClr(ChromaKeyAvid *plugin, ChromaKeyWindow *gui,
639 int x, int y, int clear)
640 : BC_Button(x, y, plugin->get_theme()->get_image_set("reset_button"))
642 this->plugin = plugin;
647 ChromaKeyClr::~ChromaKeyClr()
651 int ChromaKeyClr::handle_event()
653 plugin->config.reset(clear);
654 gui->update_gui(clear);
655 plugin->send_configure_change();
659 ChromaKeyToggle::ChromaKeyToggle (ChromaKeyAvid * plugin,
669 this->plugin = plugin;
670 this->output = output;
674 ChromaKeyToggle::handle_event ()
676 *output = get_value() ? true : false;
677 plugin->send_configure_change ();
682 ChromaKeyReset::ChromaKeyReset (ChromaKeyAvid *plugin, ChromaKeyWindow *gui,
684 : BC_GenericButton(x, y, _("Reset"))
686 this->plugin = plugin;
690 int ChromaKeyReset::handle_event ()
692 plugin->config.reset(RESET_DEFAULT_SETTINGS);
693 gui->update_gui(RESET_DEFAULT_SETTINGS);
694 plugin->send_configure_change();
698 ChromaKeyStore::ChromaKeyStore (ChromaKeyAvid *plugin, ChromaKeyWindow *gui,
700 : BC_GenericButton(x, y, _("Store"))
702 this->plugin = plugin;
706 int ChromaKeyStore::handle_event ()
708 plugin->config.store_red = plugin->config.red;
709 plugin->config.store_green = plugin->config.green;
710 plugin->config.store_blue = plugin->config.blue;
711 plugin->config.store_min_brightness = plugin->config.min_brightness;
712 plugin->config.store_max_brightness = plugin->config.max_brightness;
713 plugin->config.store_tolerance = plugin->config.tolerance;
714 plugin->config.store_saturation_start = plugin->config.saturation_start;
715 plugin->config.store_saturation_line = plugin->config.saturation_line;
716 plugin->config.store_in_slope = plugin->config.in_slope;
717 plugin->config.store_out_slope = plugin->config.out_slope;
718 plugin->config.store_alpha_offset = plugin->config.alpha_offset;
719 plugin->config.store_spill_saturation = plugin->config.spill_saturation;
720 plugin->config.store_spill_angle = plugin->config.spill_angle;
721 plugin->config.store_desaturate_only = plugin->config.desaturate_only;
722 plugin->config.store_show_mask = plugin->config.show_mask;
726 ChromaKeyRecall::ChromaKeyRecall (ChromaKeyAvid *plugin, ChromaKeyWindow *gui,
728 : BC_GenericButton(x, y, _("Recall"))
730 this->plugin = plugin;
734 int ChromaKeyRecall::handle_event ()
736 plugin->config.undo_red = plugin->config.red;
737 plugin->config.undo_green = plugin->config.green;
738 plugin->config.undo_blue = plugin->config.blue;
739 plugin->config.undo_min_brightness = plugin->config.min_brightness;
740 plugin->config.undo_max_brightness = plugin->config.max_brightness;
741 plugin->config.undo_tolerance = plugin->config.tolerance;
742 plugin->config.undo_saturation_start = plugin->config.saturation_start;
743 plugin->config.undo_saturation_line = plugin->config.saturation_line;
744 plugin->config.undo_in_slope = plugin->config.in_slope;
745 plugin->config.undo_out_slope = plugin->config.out_slope;
746 plugin->config.undo_alpha_offset = plugin->config.alpha_offset;
747 plugin->config.undo_spill_saturation = plugin->config.spill_saturation;
748 plugin->config.undo_spill_angle = plugin->config.spill_angle;
749 plugin->config.undo_desaturate_only = plugin->config.desaturate_only;
750 plugin->config.undo_show_mask = plugin->config.show_mask;
752 plugin->config.red = plugin->config.store_red;
753 plugin->config.green = plugin->config.store_green;
754 plugin->config.blue = plugin->config.store_blue;
755 plugin->config.min_brightness = plugin->config.store_min_brightness;
756 plugin->config.max_brightness = plugin->config.store_max_brightness;
757 plugin->config.tolerance = plugin->config.store_tolerance;
758 plugin->config.saturation_start = plugin->config.store_saturation_start;
759 plugin->config.saturation_line = plugin->config.store_saturation_line;
760 plugin->config.in_slope = plugin->config.store_in_slope;
761 plugin->config.out_slope = plugin->config.store_out_slope;
762 plugin->config.alpha_offset = plugin->config.store_alpha_offset;
763 plugin->config.spill_saturation = plugin->config.store_spill_saturation;
764 plugin->config.spill_angle = plugin->config.store_spill_angle;
765 plugin->config.desaturate_only = plugin->config.store_desaturate_only;
766 plugin->config.show_mask = plugin->config.store_show_mask;
768 gui->update_gui(RESET_DEFAULT_SETTINGS);
769 plugin->send_configure_change();
773 ChromaKeyExchange::ChromaKeyExchange (ChromaKeyAvid *plugin,
774 ChromaKeyWindow *gui, int x, int y)
775 : BC_GenericButton(x, y, _("Exchange"))
777 this->plugin = plugin;
781 #define CHROMAKEY_SWAP(what,typ,elem) \
782 tmp_##typ = plugin->config.what##_##elem; \
783 plugin->config.what##_##elem = plugin->config.elem; \
784 plugin->config.elem = tmp_##typ;
786 int ChromaKeyExchange::handle_event ()
791 plugin->config.undo_red = plugin->config.red;
792 plugin->config.undo_green = plugin->config.green;
793 plugin->config.undo_blue = plugin->config.blue;
794 plugin->config.undo_min_brightness = plugin->config.min_brightness;
795 plugin->config.undo_max_brightness = plugin->config.max_brightness;
796 plugin->config.undo_tolerance = plugin->config.tolerance;
797 plugin->config.undo_saturation_start = plugin->config.saturation_start;
798 plugin->config.undo_saturation_line = plugin->config.saturation_line;
799 plugin->config.undo_in_slope = plugin->config.in_slope;
800 plugin->config.undo_out_slope = plugin->config.out_slope;
801 plugin->config.undo_alpha_offset = plugin->config.alpha_offset;
802 plugin->config.undo_spill_saturation = plugin->config.spill_saturation;
803 plugin->config.undo_spill_angle = plugin->config.spill_angle;
804 plugin->config.undo_desaturate_only = plugin->config.desaturate_only;
805 plugin->config.undo_show_mask = plugin->config.show_mask;
807 CHROMAKEY_SWAP (store, flt, red)
808 CHROMAKEY_SWAP (store, flt, green)
809 CHROMAKEY_SWAP (store, flt, blue)
810 CHROMAKEY_SWAP (store, flt, min_brightness)
811 CHROMAKEY_SWAP (store, flt, max_brightness)
812 CHROMAKEY_SWAP (store, flt, tolerance)
813 CHROMAKEY_SWAP (store, flt, saturation_start)
814 CHROMAKEY_SWAP (store, flt, saturation_line)
815 CHROMAKEY_SWAP (store, flt, in_slope)
816 CHROMAKEY_SWAP (store, flt, out_slope)
817 CHROMAKEY_SWAP (store, flt, alpha_offset)
818 CHROMAKEY_SWAP (store, flt, spill_saturation)
819 CHROMAKEY_SWAP (store, flt, spill_angle)
820 CHROMAKEY_SWAP (store, bool, desaturate_only)
821 CHROMAKEY_SWAP (store, bool, show_mask)
823 gui->update_gui(RESET_DEFAULT_SETTINGS);
824 plugin->send_configure_change();
828 ChromaKeyUndo::ChromaKeyUndo (ChromaKeyAvid *plugin, ChromaKeyWindow *gui,
830 : BC_GenericButton(x, y, _("Undo"))
832 this->plugin = plugin;
836 int ChromaKeyUndo::handle_event ()
841 //CHROMAKEY_SWAP (undo, flt, red)
842 //CHROMAKEY_SWAP (undo, flt, green)
843 //CHROMAKEY_SWAP (undo, flt, blue)
844 //CHROMAKEY_SWAP (undo, flt, min_brightness)
845 //CHROMAKEY_SWAP (undo, flt, max_brightness)
846 //CHROMAKEY_SWAP (undo, flt, tolerance)
847 //CHROMAKEY_SWAP (undo, flt, saturation_start)
848 //CHROMAKEY_SWAP (undo, flt, saturation_line)
849 //CHROMAKEY_SWAP (undo, flt, in_slope)
850 //CHROMAKEY_SWAP (undo, flt, out_slope)
851 //CHROMAKEY_SWAP (undo, flt, alpha_offset)
852 //CHROMAKEY_SWAP (undo, flt, spill_saturation)
853 //CHROMAKEY_SWAP (undo, flt, spill_angle)
854 //CHROMAKEY_SWAP (undo, bool, desaturate_only)
855 //CHROMAKEY_SWAP (undo, bool, show_mask)
857 // better not to swap but restore undo values
859 plugin->config.red = plugin->config.undo_red;
860 plugin->config.green = plugin->config.undo_green;
861 plugin->config.blue = plugin->config.undo_blue;
862 plugin->config.min_brightness = plugin->config.undo_min_brightness;
863 plugin->config.max_brightness = plugin->config.undo_max_brightness;
864 plugin->config.tolerance = plugin->config.undo_tolerance;
865 plugin->config.saturation_start = plugin->config.undo_saturation_start;
866 plugin->config.saturation_line = plugin->config.undo_saturation_line;
867 plugin->config.in_slope = plugin->config.undo_in_slope;
868 plugin->config.out_slope = plugin->config.undo_out_slope;
869 plugin->config.alpha_offset = plugin->config.undo_alpha_offset;
870 plugin->config.spill_saturation = plugin->config.undo_spill_saturation;
871 plugin->config.spill_angle = plugin->config.undo_spill_angle;
872 plugin->config.desaturate_only = plugin->config.undo_desaturate_only;
873 plugin->config.show_mask = plugin->config.undo_show_mask;
875 gui->update_gui(RESET_DEFAULT_SETTINGS);
876 plugin->send_configure_change();
880 ChromaKeyUseColorPicker::ChromaKeyUseColorPicker (ChromaKeyAvid * plugin,
881 ChromaKeyWindow * gui,
883 : BC_GenericButton (x, y, _("Use color picker"))
885 this->plugin = plugin;
890 ChromaKeyUseColorPicker::handle_event ()
892 plugin->config.red = plugin->get_red ();
893 plugin->config.green = plugin->get_green ();
894 plugin->config.blue = plugin->get_blue ();
896 gui->update_sample ();
898 plugin->send_configure_change ();
902 ChromaKeyColorThread::ChromaKeyColorThread (ChromaKeyAvid * plugin,
903 ChromaKeyWindow * gui)
904 : ColorPicker (0, _("Color"))
906 this->plugin = plugin;
911 ChromaKeyColorThread::handle_new_color (int output, int alpha)
913 plugin->config.red = (float) (output & 0xff0000) / 0xff0000;
914 plugin->config.green = (float) (output & 0xff00) / 0xff00;
915 plugin->config.blue = (float) (output & 0xff) / 0xff;
917 get_gui()->unlock_window();
918 gui->lock_window("ChromaKeyColorThread::handle_new_color");
919 gui->update_sample();
920 gui->unlock_window();
921 get_gui()->lock_window("ChromaKeyColorThread::handle_new_color");
923 plugin->send_configure_change ();
929 ChromaKeyServer::ChromaKeyServer (ChromaKeyAvid * plugin)
930 : LoadServer (plugin->PluginClient::smp + 1,
931 plugin->PluginClient::smp + 1)
933 // : LoadServer (1, 1)
935 this->plugin = plugin;
939 ChromaKeyServer::init_packages ()
941 for (int i = 0; i < get_total_packages (); i++)
943 ChromaKeyPackage *pkg = (ChromaKeyPackage *) get_package (i);
944 pkg->y1 = plugin->input->get_h () * i / get_total_packages ();
945 pkg->y2 = plugin->input->get_h () * (i + 1) / get_total_packages ();
950 ChromaKeyServer::new_client ()
952 return new ChromaKeyUnit (plugin, this);
956 ChromaKeyServer::new_package ()
958 return new ChromaKeyPackage;
961 ChromaKeyPackage::ChromaKeyPackage ():LoadPackage ()
965 ChromaKeyUnit::ChromaKeyUnit (ChromaKeyAvid * plugin, ChromaKeyServer * server)
966 : LoadClient (server)
968 this->plugin = plugin;
973 #define ABS(a) (((a) < 0) ? -(a) : (a))
977 // Compute the same values in the opengl version
978 #define COMMON_VARIABLES \
979 float red = plugin->config.red; \
980 float green = plugin->config.green; \
981 float blue = plugin->config.blue; \
983 float in_slope = plugin->config.in_slope / MAX_SLOPE; \
984 float out_slope = plugin->config.out_slope / MAX_SLOPE; \
986 /* Convert RGB key to HSV key */ \
987 float hue_key, saturation_key, value_key; \
988 HSV::rgb_to_hsv(red, \
996 float tolerance = plugin->config.tolerance * 180 / MAX_VALUE; \
997 float tolerance_in = tolerance - in_slope * 180; \
998 tolerance_in = MAX(tolerance_in, 0); \
999 float tolerance_out = tolerance + out_slope * 180; \
1000 tolerance_out = MIN(tolerance_out, 180); \
1002 /* distance of wedge point from center */ \
1003 float sat_distance = plugin->config.saturation_start / MAX_VALUE; \
1004 /* XY shift of input color to get wedge point */ \
1005 float sat_x = -cos(TO_RAD(hue_key)) * sat_distance; \
1006 float sat_y = -sin(TO_RAD(hue_key)) * sat_distance; \
1007 /* minimum saturation after wedge point */ \
1008 float min_s = plugin->config.saturation_line / MAX_VALUE; \
1009 float min_s_in = min_s + in_slope; \
1010 float min_s_out = min_s - out_slope; \
1012 float min_v = plugin->config.min_brightness / MAX_VALUE; \
1013 float min_v_in = min_v + in_slope; \
1014 float min_v_out = min_v - out_slope; \
1015 /* ignore min_brightness 0 */ \
1016 if(plugin->config.min_brightness == 0) min_v_in = 0; \
1018 float max_v = plugin->config.max_brightness / MAX_VALUE; \
1019 float max_v_in = max_v - in_slope; \
1020 float max_v_out = max_v + out_slope; \
1021 /* handle wedge boundaries crossing over */ \
1022 if(max_v_in < min_v_in) max_v_in = min_v_in = (max_v_in + min_v_in) / 2; \
1023 /* ignore max_brightness 100% */ \
1024 if(plugin->config.max_brightness == MAX_VALUE) max_v_in = 1.0; \
1026 /* distance of spill wedge point from center */ \
1027 float spill_distance = sat_distance * (1.0 - plugin->config.spill_saturation / MAX_VALUE); \
1028 /* XY shift of input color to get spill wedge point */ \
1029 float spill_x = -cos(TO_RAD(hue_key)) * spill_distance; \
1030 float spill_y = -sin(TO_RAD(hue_key)) * spill_distance; \
1031 /* tolerance of the spill wedge */ \
1032 float spill_tolerance = tolerance + plugin->config.spill_angle * 90.0 / MAX_VALUE; \
1033 /* borders of the spill wedge */ \
1034 float min_h = hue_key - spill_tolerance; \
1035 float max_h = hue_key + spill_tolerance; \
1036 int desaturate_only = plugin->config.desaturate_only; \
1038 float alpha_offset = plugin->config.alpha_offset / MAX_VALUE;
1040 // shortest distance between 2 hues
1041 static float hue_distance(float h1, float h2)
1043 float result = h1 - h2;
1044 if(result < -180) result += 360;
1045 else if(result > 180) result -= 360;
1049 // shift H & S based on an X & Y offset
1050 static void shift_hs(float &h_shifted,
1057 float h_rad = TO_RAD(h);
1058 float x = cos(h_rad) * s;
1059 float y = sin(h_rad) * s;
1062 h_shifted = TO_DEG(atan2(y, x));
1063 s_shifted = hypot(x, y);
1066 template <typename component_type>
1067 void ChromaKeyUnit::process_chromakey(int components,
1070 ChromaKeyPackage *pkg)
1074 int w = plugin->input->get_w();
1076 // printf("ChromaKeyUnit::process_chromakey %d hue_key=%f min_h=%f max_h=%f\n",
1081 // printf("ChromaKeyUnit::process_chromakey %d tolerance_in=%f tolerance=%f tolerance_out=%f\n",
1086 // printf("ChromaKeyUnit::process_chromakey %d min_s_in=%f min_s=%f min_s_out=%f\n",
1091 // printf("ChromaKeyUnit::process_chromakey %d min_v_in=%f min_v=%f min_v_out=%f\n",
1096 // printf("ChromaKeyUnit::process_chromakey %d max_v_in=%f max_v=%f max_v_out=%f\n",
1102 for (int i = pkg->y1; i < pkg->y2; i++)
1104 component_type *row = (component_type *) plugin->input->get_rows ()[i];
1106 for (int j = 0; j < w; j++)
1108 float r, g, b, a = 1;
1111 r = (float) row[0] / max;
1112 g = (float) row[1] / max;
1113 b = (float) row[2] / max;
1115 else /* Convert pixel to RGB float */
1116 YUV::yuv.yuv_to_rgb_f (r, g, b, row[0], row[1], row[2]);
1121 // alpha contribution of each component of the HSV space
1122 float ah = 1, as = 1, av = 1;
1124 HSV::rgb_to_hsv (r, g, b, h, s, v);
1126 // shift the input color in XY to get the wedge point
1127 float h_shifted, s_shifted;
1128 if(!EQUIV(plugin->config.saturation_start, 0))
1143 /* Get the difference between the shifted input color & the unshifted wedge */
1144 float h_diff = hue_distance(h_shifted, hue_key);
1145 h_diff = ABS(h_diff);
1147 // alpha contribution from hue difference
1148 // outside wedge < tolerance_out < tolerance_in < inside wedge < tolerance_in < tolerance_out < outside wedge
1149 if (tolerance_out > 0)
1151 // completely inside the wedge
1152 if (h_diff < tolerance_in)
1155 // between the outer & inner slope
1156 if(h_diff < tolerance_out)
1157 ah = (h_diff - tolerance_in) / (tolerance_out - tolerance_in);
1161 // alpha contribution from saturation
1162 // outside wedge < min_s_out < min_s_in < inside wedge
1163 if(s_shifted > min_s_out)
1165 // saturation with offset applied
1166 // completely inside the wedge
1167 if(s_shifted > min_s_in)
1169 // inside the gradient
1170 if(s_shifted >= min_s_out)
1171 as = (min_s_in - s_shifted) / (min_s_in - min_s_out);
1174 // alpha contribution from brightness range
1175 // brightness range is defined by 4 in/out variables
1176 // outside wedge < min_v_out < min_v_in < inside wedge < max_v_in < max_v_out < outside wedge
1179 if(v < min_v_in || max_v_in >= 1.0)
1180 av = (min_v_in - v) / (min_v_in - min_v_out);
1181 else if(v <= max_v_in)
1183 else if(v <= max_v_out)
1184 av = (v - max_v_in) / (max_v_out - max_v_in);
1187 // combine the alpha contribution of every component into a single alpha
1191 // Spill light processing
1192 if(spill_tolerance > 0)
1194 // get the difference between the shifted input color to the unshifted spill wedge
1195 if(!EQUIV(spill_distance, 0))
1210 // Difference between the shifted hue & the unshifted hue key
1211 h_diff = hue_distance(h_shifted, hue_key);
1214 if(ABS(h_diff) < spill_tolerance)
1216 if(!desaturate_only)
1218 // the shifted input color in the unshifted wedge
1219 // gives 2 unshifted border colors & the weighting
1220 float blend = 0.5 + h_diff / spill_tolerance / 2;
1221 // shift the 2 border colors to the output wedge
1222 float min_h_shifted;
1223 float min_s_shifted;
1224 shift_hs(min_h_shifted,
1230 float max_h_shifted;
1231 float max_s_shifted;
1232 shift_hs(max_h_shifted,
1239 // blend the shifted border colors using the unshifted weighting
1240 // the only thing which doesn't restore the key color & doesn't make an edge is
1241 // fading the saturation to 0 in the middle
1246 // s = max_s_shifted * (blend - 0.5) / 0.5;
1255 // s = min_s_shifted * (0.5 - blend) / 0.5;
1261 else // !desaturate_only
1264 // fade the saturation to 0 in the middle
1265 s *= ABS(h_diff) / spill_tolerance;
1269 HSV::hsv_to_rgb (r, g, b, h, s, v);
1274 row[0] = (component_type) ((float) r * max);
1275 row[1] = (component_type) ((float) g * max);
1276 row[2] = (component_type) ((float) b * max);
1279 YUV::yuv.rgb_to_yuv_f(r, g, b, row[0], row[1], row[2]);
1284 CLAMP (a, 0.0, 1.0);
1286 if (plugin->config.show_mask)
1290 row[0] = (component_type) ((float) a * max);
1291 row[1] = (component_type) ((float) max / 2);
1292 row[2] = (component_type) ((float) max / 2);
1296 row[0] = (component_type) ((float) a * max);
1297 row[1] = (component_type) ((float) a * max);
1298 row[2] = (component_type) ((float) a * max);
1302 /* Multiply alpha and put back in frame */
1303 if (components == 4)
1305 row[3] = MIN ((component_type) (a * max), row[3]);
1309 row[0] = (component_type) ((float) a * row[0]);
1310 row[1] = (component_type) ((float) a * (row[1] - (max / 2 + 1)) +
1312 row[2] = (component_type) ((float) a * (row[2] - (max / 2 + 1)) +
1317 row[0] = (component_type) ((float) a * row[0]);
1318 row[1] = (component_type) ((float) a * row[1]);
1319 row[2] = (component_type) ((float) a * row[2]);
1329 void ChromaKeyUnit::process_package(LoadPackage *package)
1331 ChromaKeyPackage *pkg = (ChromaKeyPackage*)package;
1333 switch(plugin->input->get_color_model())
1336 process_chromakey<float> (3, 1.0, 0, pkg);
1339 process_chromakey<float> ( 4, 1.0, 0, pkg);
1342 process_chromakey<unsigned char> ( 3, 0xff, 0, pkg);
1345 process_chromakey<unsigned char> ( 4, 0xff, 0, pkg);
1348 process_chromakey<unsigned char> ( 3, 0xff, 1, pkg);
1351 process_chromakey<unsigned char> ( 4, 0xff, 1, pkg);
1354 process_chromakey<uint16_t> (3, 0xffff, 1, pkg);
1356 case BC_YUVA16161616:
1357 process_chromakey<uint16_t> (4, 0xffff, 1, pkg);
1364 REGISTER_PLUGIN(ChromaKeyAvid)
1368 ChromaKeyAvid::ChromaKeyAvid(PluginServer *server)
1369 : PluginVClient(server)
1374 ChromaKeyAvid::~ChromaKeyAvid()
1376 if(engine) delete engine;
1380 int ChromaKeyAvid::process_buffer(VFrame *frame,
1381 int64_t start_position,
1384 load_configuration();
1385 this->input = frame;
1386 this->output = frame;
1393 if(get_use_opengl()) return run_opengl();
1395 if(!engine) engine = new ChromaKeyServer(this);
1396 engine->process_packages();
1401 const char* ChromaKeyAvid::plugin_title() { return N_("Chroma key (Avid)"); }
1402 int ChromaKeyAvid::is_realtime() { return 1; }
1405 LOAD_CONFIGURATION_MACRO(ChromaKeyAvid, ChromaKeyConfig)
1408 void ChromaKeyAvid::save_data(KeyFrame * keyframe)
1411 output.set_shared_output(keyframe->xbuf);
1412 output.tag.set_title("CHROMAKEY_AVID");
1413 output.tag.set_property("RED", config.red);
1414 output.tag.set_property("GREEN", config.green);
1415 output.tag.set_property("BLUE", config.blue);
1416 output.tag.set_property("MIN_BRIGHTNESS", config.min_brightness);
1417 output.tag.set_property("MAX_BRIGHTNESS", config.max_brightness);
1418 output.tag.set_property("SATURATION_START", config.saturation_start);
1419 output.tag.set_property("SATURATION_LINE", config.saturation_line);
1420 output.tag.set_property("TOLERANCE", config.tolerance);
1421 output.tag.set_property("IN_SLOPE", config.in_slope);
1422 output.tag.set_property("OUT_SLOPE", config.out_slope);
1423 output.tag.set_property("ALPHA_OFFSET", config.alpha_offset);
1424 output.tag.set_property("SPILL_SATURATION", config.spill_saturation);
1425 output.tag.set_property("SPILL_ANGLE", config.spill_angle);
1426 output.tag.set_property("DESATURATE_ONLY", config.desaturate_only);
1427 output.tag.set_property("SHOW_MASK", config.show_mask);
1428 output.append_tag();
1429 output.tag.set_title("/CHROMAKEY_AVID");
1430 output.append_tag();
1431 output.append_newline();
1432 output.terminate_string();
1435 void ChromaKeyAvid::read_data(KeyFrame * keyframe)
1439 input.set_shared_input(keyframe->xbuf);
1441 while( !input.read_tag() )
1443 if( input.tag.title_is("CHROMAKEY_AVID") )
1445 config.red = input.tag.get_property("RED", config.red);
1446 config.green = input.tag.get_property("GREEN", config.green);
1447 config.blue = input.tag.get_property("BLUE", config.blue);
1448 config.min_brightness =
1449 input.tag.get_property("MIN_BRIGHTNESS", config.min_brightness);
1450 config.max_brightness =
1451 input.tag.get_property("MAX_BRIGHTNESS", config.max_brightness);
1452 config.saturation_start =
1453 input.tag.get_property("SATURATION_START", config.saturation_start);
1454 config.saturation_line =
1455 input.tag.get_property("SATURATION_LINE", config.saturation_line);
1457 input.tag.get_property("TOLERANCE", config.tolerance);
1459 input.tag.get_property("IN_SLOPE", config.in_slope);
1461 input.tag.get_property("OUT_SLOPE", config.out_slope);
1462 config.alpha_offset =
1463 input.tag.get_property("ALPHA_OFFSET", config.alpha_offset);
1464 config.spill_saturation =
1465 input.tag.get_property("SPILL_SATURATION", config.spill_saturation);
1466 config.spill_angle =
1467 input.tag.get_property("SPILL_ANGLE", config.spill_angle);
1468 config.desaturate_only =
1469 input.tag.get_property("DESATURATE_ONLY", config.desaturate_only);
1471 input.tag.get_property("SHOW_MASK", config.show_mask);
1473 config.undo_red = config.red;
1474 config.undo_green = config.green;
1475 config.undo_blue = config.blue;
1476 config.undo_min_brightness = config.min_brightness;
1477 config.undo_max_brightness = config.max_brightness;
1478 config.undo_tolerance = config.tolerance;
1479 config.undo_saturation_start = config.saturation_start;
1480 config.undo_saturation_line = config.saturation_line;
1481 config.undo_in_slope = config.in_slope;
1482 config.undo_out_slope = config.out_slope;
1483 config.undo_alpha_offset = config.alpha_offset;
1484 config.undo_spill_saturation = config.spill_saturation;
1485 config.undo_spill_angle = config.spill_angle;
1486 config.undo_desaturate_only = config.desaturate_only;
1487 config.undo_show_mask = config.show_mask;
1493 NEW_WINDOW_MACRO(ChromaKeyAvid, ChromaKeyWindow)
1496 void ChromaKeyAvid::update_gui()
1500 load_configuration();
1501 ChromaKeyWindow *window = (ChromaKeyWindow*)thread->window;
1502 window->lock_window();
1503 window->update_gui(RESET_ALL);
1504 window->unlock_window();
1508 void ChromaKeyWindow::update_gui(int clear)
1510 ChromaKeyConfig &config = plugin->config;
1516 case RESET_MIN_BRIGHTNESS:
1517 min_brightness->update(config.min_brightness);
1518 min_brightness_text->update(config.min_brightness);
1520 case RESET_MAX_BRIGHTNESS:
1521 max_brightness->update(config.max_brightness);
1522 max_brightness_text->update(config.max_brightness);
1524 case RESET_TOLERANCE:
1525 tolerance->update(config.tolerance);
1526 tolerance_text->update(config.tolerance);
1528 case RESET_SATURATION_START:
1529 saturation_start->update(config.saturation_start);
1530 saturation_start_text->update(config.saturation_start);
1532 case RESET_SATURATION_LINE:
1533 saturation_line->update(config.saturation_line);
1534 saturation_line_text->update(config.saturation_line);
1536 case RESET_IN_SLOPE:
1537 in_slope->update(config.in_slope);
1538 in_slope_text->update(config.in_slope);
1540 case RESET_OUT_SLOPE:
1541 out_slope->update(config.out_slope);
1542 out_slope_text->update(config.out_slope);
1544 case RESET_ALPHA_OFFSET:
1545 alpha_offset->update(config.alpha_offset);
1546 alpha_offset_text->update(config.alpha_offset);
1548 case RESET_SPILL_SATURATION:
1549 spill_saturation->update(config.spill_saturation);
1550 spill_saturation_text->update(config.spill_saturation);
1552 case RESET_SPILL_ANGLE:
1553 spill_angle->update(config.spill_angle);
1554 spill_angle_text->update(config.spill_angle);
1557 case RESET_DEFAULT_SETTINGS:
1559 min_brightness->update(config.min_brightness);
1560 min_brightness_text->update(config.min_brightness);
1561 max_brightness->update(config.max_brightness);
1562 max_brightness_text->update(config.max_brightness);
1563 saturation_start->update(config.saturation_start);
1564 saturation_start_text->update(config.saturation_start);
1565 saturation_line->update(config.saturation_line);
1566 saturation_line_text->update(config.saturation_line);
1567 tolerance->update(config.tolerance);
1568 tolerance_text->update(config.tolerance);
1569 in_slope->update(config.in_slope);
1570 in_slope_text->update(config.in_slope);
1571 out_slope->update(config.out_slope);
1572 out_slope_text->update(config.out_slope);
1573 alpha_offset->update(config.alpha_offset);
1574 alpha_offset_text->update(config.alpha_offset);
1575 spill_saturation->update(config.spill_saturation);
1576 spill_saturation_text->update(config.spill_saturation);
1577 spill_angle->update(config.spill_angle);
1578 spill_angle_text->update(config.spill_angle);
1579 desaturate_only->update(config.desaturate_only);
1580 show_mask->update(config.show_mask);
1588 int ChromaKeyAvid::handle_opengl()
1592 ChromaKeyAvid *plugin = this;
1595 static const char *yuv_shader =
1596 "const vec3 black = vec3(0.0, 0.5, 0.5);\n"
1597 "uniform mat3 yuv_to_rgb_matrix;\n"
1598 "uniform mat3 rgb_to_yuv_matrix;\n"
1599 "uniform float yminf;\n"
1601 "vec4 yuv_to_rgb(vec4 color)\n"
1603 " color.rgb -= vec3(yminf, 0.5, 0.5);\n"
1604 " color.rgb = yuv_to_rgb_matrix * color.rgb;\n"
1608 "vec4 rgb_to_yuv(vec4 color)\n"
1610 " color.rgb = rgb_to_yuv_matrix * color.rgb;\n"
1611 " color.rgb += vec3(yminf, 0.5, 0.5);\n"
1615 static const char *rgb_shader =
1616 "const vec3 black = vec3(0.0, 0.0, 0.0);\n"
1618 "vec4 yuv_to_rgb(vec4 color)\n"
1622 "vec4 rgb_to_yuv(vec4 color)\n"
1627 static const char *hsv_shader =
1628 "vec4 rgb_to_hsv(vec4 color)\n"
1630 RGB_TO_HSV_FRAG("color")
1634 "vec4 hsv_to_rgb(vec4 color)\n"
1636 HSV_TO_RGB_FRAG("color")
1641 static const char *show_rgbmask_shader =
1642 "vec4 show_mask(vec4 color, vec4 color2)\n"
1644 " return vec4(1.0, 1.0, 1.0, min(color.a, color2.a));"
1647 static const char *show_yuvmask_shader =
1648 "vec4 show_mask(vec4 color, vec4 color2)\n"
1650 " return vec4(1.0, 0.5, 0.5, min(color.a, color2.a));"
1653 static const char *nomask_shader =
1654 "vec4 show_mask(vec4 color, vec4 color2)\n"
1656 " return vec4(color.rgb, min(color.a, color2.a));"
1659 get_output()->to_texture();
1660 get_output()->enable_opengl();
1661 get_output()->init_screen();
1663 const char *shader_stack[16];
1664 memset(shader_stack,0, sizeof(shader_stack));
1665 int current_shader = 0;
1667 shader_stack[current_shader++] = \
1668 !BC_CModels::is_yuv(get_output()->get_color_model()) ?
1669 rgb_shader : yuv_shader;
1670 shader_stack[current_shader++] = hsv_shader;
1671 shader_stack[current_shader++] = !config.show_mask ? nomask_shader :
1672 !BC_CModels::is_yuv(get_output()->get_color_model()) ?
1673 show_rgbmask_shader : show_yuvmask_shader ;
1674 extern unsigned char _binary_chromakeyavid_sl_start[];
1675 static const char *shader_frag = (char*)_binary_chromakeyavid_sl_start;
1676 shader_stack[current_shader++] = shader_frag;
1678 shader_stack[current_shader] = 0;
1679 unsigned int shader = VFrame::make_shader(shader_stack);
1681 glUseProgram(shader);
1682 glUniform1i(glGetUniformLocation(shader, "tex"), 0);
1683 glUniform1f(glGetUniformLocation(shader, "red"), red);
1684 glUniform1f(glGetUniformLocation(shader, "green"), green);
1685 glUniform1f(glGetUniformLocation(shader, "blue"), blue);
1686 glUniform1f(glGetUniformLocation(shader, "in_slope"), in_slope);
1687 glUniform1f(glGetUniformLocation(shader, "out_slope"), out_slope);
1688 glUniform1f(glGetUniformLocation(shader, "tolerance"), tolerance);
1689 glUniform1f(glGetUniformLocation(shader, "tolerance_in"), tolerance_in);
1690 glUniform1f(glGetUniformLocation(shader, "tolerance_out"), tolerance_out);
1691 glUniform1f(glGetUniformLocation(shader, "sat_x"), sat_x);
1692 glUniform1f(glGetUniformLocation(shader, "sat_y"), sat_y);
1693 glUniform1f(glGetUniformLocation(shader, "min_s"), min_s);
1694 glUniform1f(glGetUniformLocation(shader, "min_s_in"), min_s_in);
1695 glUniform1f(glGetUniformLocation(shader, "min_s_out"), min_s_out);
1696 glUniform1f(glGetUniformLocation(shader, "min_v"), min_v);
1697 glUniform1f(glGetUniformLocation(shader, "min_v_in"), min_v_in);
1698 glUniform1f(glGetUniformLocation(shader, "min_v_out"), min_v_out);
1699 glUniform1f(glGetUniformLocation(shader, "max_v"), max_v);
1700 glUniform1f(glGetUniformLocation(shader, "max_v_in"), max_v_in);
1701 glUniform1f(glGetUniformLocation(shader, "max_v_out"), max_v_out);
1702 glUniform1f(glGetUniformLocation(shader, "spill_distance"), spill_distance);
1703 glUniform1f(glGetUniformLocation(shader, "spill_x"), spill_x);
1704 glUniform1f(glGetUniformLocation(shader, "spill_y"), spill_y);
1705 glUniform1f(glGetUniformLocation(shader, "spill_tolerance"), spill_tolerance);
1706 glUniform1f(glGetUniformLocation(shader, "min_h"), min_h);
1707 glUniform1f(glGetUniformLocation(shader, "max_h"), max_h);
1708 glUniform1i(glGetUniformLocation(shader, "desaturate_only"), desaturate_only);
1709 glUniform1f(glGetUniformLocation(shader, "alpha_offset"), alpha_offset);
1710 glUniform1f(glGetUniformLocation(shader, "hue_key"), hue_key);
1711 glUniform1f(glGetUniformLocation(shader, "saturation_key"), saturation_key);
1712 glUniform1f(glGetUniformLocation(shader, "value_key"), value_key);
1713 if( BC_CModels::is_yuv(get_output()->get_color_model()) )
1714 BC_GL_COLORS(shader);
1717 get_output()->bind_texture(0);
1718 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1719 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1721 if(BC_CModels::components(get_output()->get_color_model()) == 3)
1724 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1725 get_output()->clear_pbuffer();
1727 get_output()->draw_texture();
1730 get_output()->set_opengl_state(VFrame::SCREEN);
1731 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1732 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1733 glDisable(GL_BLEND);