r780: fix to chromakey by Jerome
[cinelerra_cv/mob.git] / plugins / chromakey-hsv / chromakey.C
blobb14a93b61b0f895668e871ee3d22641e190884c0
1 #include "bcdisplayinfo.h"
2 #include "chromakey.h"
3 #include "clip.h"
4 #include "defaults.h"
5 #include "filexml.h"
6 #include "guicast.h"
7 #include "keyframe.h"
8 #include "language.h"
9 #include "loadbalance.h"
10 #include "picon_png.h"
11 #include "plugincolors.h"
12 #include "pluginvclient.h"
13 #include "vframe.h"
15 #include <stdint.h>
16 #include <string.h>
22 ChromaKeyConfig::ChromaKeyConfig ()
24   red = 0.0;
25   green = 1.0;
26   blue = 0.0;
28   min_brightness = 50.0;
29   max_brightness = 100.0;
30   tolerance = 15.0;
31   saturation = 0.0;
32   min_saturation = 50.0;
34   in_slope = 2;
35   out_slope = 2;
36   alpha_offset = 0;
38   spill_threshold = 0.0;
39   spill_amount = 90.0;
41   show_mask = 0;
46 void
47 ChromaKeyConfig::copy_from (ChromaKeyConfig & src)
49   red = src.red;
50   green = src.green;
51   blue = src.blue;
52   spill_threshold = src.spill_threshold;
53   spill_amount = src.spill_amount;
54   min_brightness = src.min_brightness;
55   max_brightness = src.max_brightness;
56   saturation = src.saturation;
57   min_saturation = src.min_saturation;
58   tolerance = src.tolerance;
59   in_slope = src.in_slope;
60   out_slope = src.out_slope;
61   alpha_offset = src.alpha_offset;
62   show_mask = src.show_mask;
65 int
66 ChromaKeyConfig::equivalent (ChromaKeyConfig & src)
68   return (EQUIV (red, src.red) &&
69           EQUIV (green, src.green) &&
70           EQUIV (blue, src.blue) &&
71           EQUIV (spill_threshold, src.spill_threshold) &&
72           EQUIV (spill_amount, src.spill_amount) &&
73           EQUIV (min_brightness, src.min_brightness) &&
74           EQUIV (max_brightness, src.max_brightness) &&
75           EQUIV (saturation, src.saturation) &&
76           EQUIV (min_saturation, src.min_saturation) &&
77           EQUIV (tolerance, src.tolerance) &&
78           EQUIV (in_slope, src.in_slope) &&
79           EQUIV (out_slope, src.out_slope) &&
80           EQUIV (show_mask, src.show_mask) &&
81           EQUIV (alpha_offset, src.alpha_offset));
84 void
85 ChromaKeyConfig::interpolate (ChromaKeyConfig & prev,
86                               ChromaKeyConfig & next,
87                               int64_t prev_frame,
88                               int64_t next_frame, int64_t current_frame)
90   double next_scale =
91     (double) (current_frame - prev_frame) / (next_frame - prev_frame);
92   double prev_scale =
93     (double) (next_frame - current_frame) / (next_frame - prev_frame);
95   this->red = prev.red * prev_scale + next.red * next_scale;
96   this->green = prev.green * prev_scale + next.green * next_scale;
97   this->blue = prev.blue * prev_scale + next.blue * next_scale;
98   this->spill_threshold =
99     prev.spill_threshold * prev_scale + next.spill_threshold * next_scale;
100   this->spill_amount =
101     prev.spill_amount * prev_scale + next.tolerance * next_scale;
102   this->min_brightness =
103     prev.min_brightness * prev_scale + next.min_brightness * next_scale;
104   this->max_brightness =
105     prev.max_brightness * prev_scale + next.max_brightness * next_scale;
106   this->saturation =
107     prev.saturation * prev_scale + next.saturation * next_scale;
108   this->min_saturation =
109     prev.min_saturation * prev_scale + next.min_saturation * next_scale;
110   this->tolerance = prev.tolerance * prev_scale + next.tolerance * next_scale;
111   this->in_slope = prev.in_slope * prev_scale + next.in_slope * next_scale;
112   this->out_slope = prev.out_slope * prev_scale + next.out_slope * next_scale;
113   this->alpha_offset =
114     prev.alpha_offset * prev_scale + next.alpha_offset * next_scale;
115   this->show_mask = next.show_mask;
120 ChromaKeyConfig::get_color ()
122   int red = (int) (CLIP (this->red, 0, 1) * 0xff);
123   int green = (int) (CLIP (this->green, 0, 1) * 0xff);
124   int blue = (int) (CLIP (this->blue, 0, 1) * 0xff);
125   return (red << 16) | (green << 8) | blue;
130 ChromaKeyWindow::ChromaKeyWindow (ChromaKey * plugin, int x, int y):BC_Window (plugin->gui_string,
131            x,
132            y, 370, 500, 370, 500, 0, 0, 1)
134   this->plugin = plugin;
135   color_thread = 0;
138 ChromaKeyWindow::~ChromaKeyWindow ()
140   delete color_thread;
143 void
144 ChromaKeyWindow::create_objects ()
146   int y = 10, x1 = 150, x2 = 10;
147   int x = 30;
149   BC_Title *title;
150   add_subwindow (title = new BC_Title (x2, y, _("Color:")));
152   add_subwindow (color = new ChromaKeyColor (plugin, this, x, y + 25));
154   add_subwindow (sample =
155                  new BC_SubWindow (x + color->get_w () + 10, y, 100, 50));
156   y += sample->get_h () + 10;
158   add_subwindow (use_colorpicker =
159                  new ChromaKeyUseColorPicker (plugin, this, x, y));
160   y += 30;
162   add_subwindow (new BC_Title (x2, y, _("Key parameters:")));
163   y += 25;
164   add_subwindow (new BC_Title (x, y, _("Hue Tolerance:")));
165   add_subwindow (tolerance = new ChromaKeyTolerance (plugin, x1, y));
166   y += 25;
167   add_subwindow (new BC_Title (x, y, _("Min. Brightness:")));
168   add_subwindow (min_brightness = new ChromaKeyMinBrightness (plugin, x1, y));
169   y += 25;
170   add_subwindow (new BC_Title (x, y, _("Max. Brightness:")));
171   add_subwindow (max_brightness = new ChromaKeyMaxBrightness (plugin, x1, y));
172   y += 25;
173   add_subwindow (new BC_Title (x, y, _("Saturation Offset:")));
174   add_subwindow (saturation = new ChromaKeySaturation (plugin, x1, y));
175   y += 25;
176   add_subwindow (new BC_Title (x, y, _("Min Saturation:")));
177   add_subwindow (min_saturation = new ChromaKeyMinSaturation (plugin, x1, y));
178   y += 30;
180   add_subwindow (new BC_Title (x2, y, _("Mask tweaking:")));
181   y += 25;
182   add_subwindow (new BC_Title (x, y, _("In Slope:")));
183   add_subwindow (in_slope = new ChromaKeyInSlope (plugin, x1, y));
184   y += 25;
185   add_subwindow (new BC_Title (x, y, _("Out Slope:")));
186   add_subwindow (out_slope = new ChromaKeyOutSlope (plugin, x1, y));
187   y += 25;
188   add_subwindow (new BC_Title (x, y, _("Alpha Offset:")));
189   add_subwindow (alpha_offset = new ChromaKeyAlphaOffset (plugin, x1, y));
190   y += 30;
192   add_subwindow (new BC_Title (x2, y, _("Spill light control:")));
193   y += 25;
194   add_subwindow (new BC_Title (x, y, _("Spill Threshold:")));
195   add_subwindow (spill_threshold =
196                  new ChromaKeySpillThreshold (plugin, x1, y));
197   y += 25;
198   add_subwindow (new BC_Title (x, y, _("Spill Compensation:")));
199   add_subwindow (spill_amount = new ChromaKeySpillAmount (plugin, x1, y));
200   y += 25;
201   add_subwindow (show_mask = new ChromaKeyShowMask (plugin, x, y));
203   color_thread = new ChromaKeyColorThread (plugin, this);
205   update_sample ();
206   show_window ();
207   flush ();
210 void
211 ChromaKeyWindow::update_sample ()
213   sample->set_color (plugin->config.get_color ());
214   sample->draw_box (0, 0, sample->get_w (), sample->get_h ());
215   sample->set_color (BLACK);
216   sample->draw_rectangle (0, 0, sample->get_w (), sample->get_h ());
217   sample->flash ();
222 WINDOW_CLOSE_EVENT (ChromaKeyWindow)
223   ChromaKeyColor::ChromaKeyColor (ChromaKey * plugin,
224                                   ChromaKeyWindow * gui, int x, int y):
225 BC_GenericButton (x, y, _("Color..."))
227   this->plugin = plugin;
228   this->gui = gui;
232 ChromaKeyColor::handle_event ()
234   gui->color_thread->start_window (plugin->config.get_color (), 0xff);
235   return 1;
241 ChromaKeyMinBrightness::ChromaKeyMinBrightness (ChromaKey * plugin, int x, int y):BC_FSlider (x,
242             y,
243             0,
244             200, 200, (float) 0, (float) 100, plugin->config.min_brightness)
246   this->plugin = plugin;
247   set_precision (0.01);
251 ChromaKeyMinBrightness::handle_event ()
253   plugin->config.min_brightness = get_value ();
254   plugin->send_configure_change ();
255   return 1;
258 ChromaKeyMaxBrightness::ChromaKeyMaxBrightness (ChromaKey * plugin, int x, int y):BC_FSlider (x,
259             y,
260             0,
261             200, 200, (float) 0, (float) 100, plugin->config.max_brightness)
263   this->plugin = plugin;
264   set_precision (0.01);
268 ChromaKeyMaxBrightness::handle_event ()
270   plugin->config.max_brightness = get_value ();
271   plugin->send_configure_change ();
272   return 1;
276 ChromaKeySaturation::ChromaKeySaturation (ChromaKey * plugin, int x, int y):BC_FSlider (x,
277             y,
278             0, 200, 200, (float) 0, (float) 100, plugin->config.saturation)
280   this->plugin = plugin;
281   set_precision (0.01);
285 ChromaKeySaturation::handle_event ()
287   plugin->config.saturation = get_value ();
288   plugin->send_configure_change ();
289   return 1;
292 ChromaKeyMinSaturation::ChromaKeyMinSaturation (ChromaKey * plugin, int x, int y):BC_FSlider (x,
293             y,
294             0,
295             200, 200, (float) 0, (float) 100, plugin->config.min_saturation)
297   this->plugin = plugin;
298   set_precision (0.01);
302 ChromaKeyMinSaturation::handle_event ()
304   plugin->config.min_saturation = get_value ();
305   plugin->send_configure_change ();
306   return 1;
310 ChromaKeyTolerance::ChromaKeyTolerance (ChromaKey * plugin, int x, int y):BC_FSlider (x,
311             y,
312             0, 200, 200, (float) 0, (float) 100, plugin->config.tolerance)
314   this->plugin = plugin;
315   set_precision (0.01);
319 ChromaKeyTolerance::handle_event ()
321   plugin->config.tolerance = get_value ();
322   plugin->send_configure_change ();
323   return 1;
328 ChromaKeyInSlope::ChromaKeyInSlope (ChromaKey * plugin, int x, int y):BC_FSlider (x,
329             y,
330             0, 200, 200, (float) 0, (float) 20, plugin->config.in_slope)
332   this->plugin = plugin;
333   set_precision (0.01);
337 ChromaKeyInSlope::handle_event ()
339   plugin->config.in_slope = get_value ();
340   plugin->send_configure_change ();
341   return 1;
345 ChromaKeyOutSlope::ChromaKeyOutSlope (ChromaKey * plugin, int x, int y):BC_FSlider (x,
346             y,
347             0, 200, 200, (float) 0, (float) 20, plugin->config.out_slope)
349   this->plugin = plugin;
350   set_precision (0.01);
354 ChromaKeyOutSlope::handle_event ()
356   plugin->config.out_slope = get_value ();
357   plugin->send_configure_change ();
358   return 1;
362 ChromaKeyAlphaOffset::ChromaKeyAlphaOffset (ChromaKey * plugin, int x, int y):BC_FSlider (x,
363             y,
364             0,
365             200, 200, (float) -100, (float) 100, plugin->config.alpha_offset)
367   this->plugin = plugin;
368   set_precision (0.01);
372 ChromaKeyAlphaOffset::handle_event ()
374   plugin->config.alpha_offset = get_value ();
375   plugin->send_configure_change ();
376   return 1;
379 ChromaKeyShowMask::ChromaKeyShowMask (ChromaKey * plugin, int x, int y):BC_CheckBox (x, y, plugin->config.show_mask,
380              _
381              ("Show Mask"))
383   this->plugin = plugin;
388 ChromaKeyShowMask::handle_event ()
390   plugin->config.show_mask = get_value ();
391   plugin->send_configure_change ();
392   return 1;
395 ChromaKeyUseColorPicker::ChromaKeyUseColorPicker (ChromaKey * plugin, ChromaKeyWindow * gui, int x, int y):BC_GenericButton (x, y,
396                   _
397                   ("Use color picker"))
399   this->plugin = plugin;
400   this->gui = gui;
404 ChromaKeyUseColorPicker::handle_event ()
406   plugin->config.red = plugin->get_red ();
407   plugin->config.green = plugin->get_green ();
408   plugin->config.blue = plugin->get_blue ();
409   gui->update_sample ();
410   plugin->send_configure_change ();
411   return 1;
416 ChromaKeySpillThreshold::ChromaKeySpillThreshold (ChromaKey * plugin, int x, int y):BC_FSlider (x,
417             y,
418             0,
419             200, 200, (float) 0, (float) 100, plugin->config.spill_threshold)
421   this->plugin = plugin;
422   set_precision (0.01);
426 ChromaKeySpillThreshold::handle_event ()
428   plugin->config.spill_threshold = get_value ();
429   plugin->send_configure_change ();
430   return 1;
433 ChromaKeySpillAmount::ChromaKeySpillAmount (ChromaKey * plugin, int x, int y):BC_FSlider (x,
434             y,
435             0, 200, 200, (float) 0, (float) 100, plugin->config.spill_amount)
437   this->plugin = plugin;
438   set_precision (0.01);
442 ChromaKeySpillAmount::handle_event ()
444   plugin->config.spill_amount = get_value ();
445   plugin->send_configure_change ();
446   return 1;
454 ChromaKeyColorThread::ChromaKeyColorThread (ChromaKey * plugin, ChromaKeyWindow * gui):ColorThread (1,
455              _
456              ("Inner color"))
458   this->plugin = plugin;
459   this->gui = gui;
463 ChromaKeyColorThread::handle_new_color (int output, int alpha)
465   plugin->config.red = (float) (output & 0xff0000) / 0xff0000;
466   plugin->config.green = (float) (output & 0xff00) / 0xff00;
467   plugin->config.blue = (float) (output & 0xff) / 0xff;
468   gui->update_sample ();
469   plugin->send_configure_change ();
470   return 1;
480 PLUGIN_THREAD_OBJECT (ChromaKey, ChromaKeyThread, ChromaKeyWindow) ChromaKeyServer::ChromaKeyServer (ChromaKey * plugin):LoadServer (plugin->PluginClient::smp + 1,
481             plugin->PluginClient::smp +
482             1)
484   this->plugin = plugin;
487 void
488 ChromaKeyServer::init_packages ()
490   for (int i = 0; i < get_total_packages (); i++)
491     {
492       ChromaKeyPackage *pkg = (ChromaKeyPackage *) get_package (i);
493       pkg->y1 = plugin->input->get_h () * i / get_total_packages ();
494       pkg->y2 = plugin->input->get_h () * (i + 1) / get_total_packages ();
495     }
498 LoadClient *
499 ChromaKeyServer::new_client ()
501   return new ChromaKeyUnit (plugin, this);
504 LoadPackage *
505 ChromaKeyServer::new_package ()
507   return new ChromaKeyPackage;
512 ChromaKeyPackage::ChromaKeyPackage ():LoadPackage ()
516 ChromaKeyUnit::ChromaKeyUnit (ChromaKey * plugin, ChromaKeyServer * server):LoadClient
517   (server)
519   this->plugin = plugin;
524 #define ABS(a) ((a<0)?-(a):a)
526 template < typename component_type > void
527 ChromaKeyUnit::process_chromakey (int components, component_type max,
528                                   bool use_yuv, ChromaKeyPackage * pkg)
530   int w = plugin->input->get_w ();
532   float red = plugin->config.red;
533   float green = plugin->config.green;
534   float blue = plugin->config.blue;
536   float hk, sk, vk;
537   HSV::rgb_to_hsv (plugin->config.red,
538                    plugin->config.green, plugin->config.blue, hk, sk, vk);
540   float in_slope = plugin->config.in_slope / 100;
541   float out_slope = plugin->config.out_slope / 100;
543   float tolerance = plugin->config.tolerance / 100;
544   float tolerance_in = tolerance - in_slope;
545   float tolerance_out = tolerance + out_slope;
547   float sat = plugin->config.saturation / 100;
548   float min_s = plugin->config.min_saturation / 100;
549   float min_s_in = min_s + in_slope;
550   float min_s_out = min_s - out_slope;
552   float min_v = plugin->config.min_brightness / 100;
553   float min_v_in = min_v + in_slope;
554   float min_v_out = min_v - out_slope;
556   float max_v = plugin->config.max_brightness / 100;
557   float max_v_in = max_v - in_slope;
558   float max_v_out = max_v + out_slope;
560   float spill_threshold = plugin->config.spill_threshold / 100;
561   float spill_amount = 1 - plugin->config.spill_amount / 100;
563   float alpha_offset = plugin->config.alpha_offset / 100;
565 #if 0
566 #define MAX3(a,b,c) MAX(MAX(a,b),c)
568   int key_main_component;
570   // Find the key color
572   if (0 == MAX3 (red, green, blue))
573     spill_threshold = 0;        /* if the key color is black, there's no spill */
574   else if (red == MAX3 (red, green, blue))
575     key_main_component = 0;
576   else if (green == MAX3 (red, green, blue))
577     key_main_component = 1;
578   else
579     key_main_component = 2;
580   printf ("Key color: %s\n",
581           (key_main_component =
582            0) ? "red" : ((key_main_component = 1) ? "green" : "blue"));
584   printf ("Key HSV: %f, %f, %f\n", hk, sk, vk);
585   printf ("Min Sat: %f \tMin V: %f\n", min_s, min_v);
586   printf ("Min Hue: %f \tMax Hue: %f\n", min_hue, max_hue);
587 #endif
589   for (int i = pkg->y1; i < pkg->y2; i++)
590     {
591       component_type *row = (component_type *) plugin->input->get_rows ()[i];
593       for (int j = 0; j < w; j++)
594         {
595           float a = 1;
597           float r = (float) row[0] / max;
598           float g = (float) row[1] / max;
599           float b = (float) row[2] / max;
601           float h, s, v;
603           float av = 1, ah = 1, as = 1, avm = 1;
604           bool has_match = true;
606           if (use_yuv)
607             {
608 /* Convert pixel to RGB float */
609               float y = r;
610               float u = g;
611               float v = b;
612               YUV::yuv_to_rgb_f (r, g, b, y, u - 0.5, v - 0.5);
613             }
615           HSV::rgb_to_hsv (r, g, b, h, s, v);
617           // First, test if the hue is in range
618           if (tolerance == 0)
619             ah = 1;
620           else if (ABS (h - hk) < tolerance_in * 180)
621             ah = 0;
622           else if ((out_slope != 0) && (ABS (h - hk) < tolerance * 180))
623             ah = ABS (h - hk) / tolerance / 360;        /* we scale alpha between 0 and 1/2 */
624           else if (ABS (h - hk) < tolerance_out * 180)
625             ah = 0.5 + ABS (h - hk) / tolerance_out / 360;      /* we scale alpha between 1/2 and 1 */
626           else
627             has_match = false;
629           // Check if the saturation matches
630           if (has_match)
631             {
632               if (min_s == 0)
633                 as = 0;
634               else if (s - sat >= min_s_in)
635                 as = 0;
636               else if ((out_slope != 0) && (s - sat > min_s))
637                 as = (s - sat - min_s) / (min_s * 2); 
638               else if (s - sat > min_s_out)
639                 as = 0.5 + (s - sat - min_s_out) / (min_s_out * 2);
640               else
641                 has_match = false;
642             }
644           // Check if the value is more than the minimun
645           if (has_match)
646             {
647               if (min_v == 0)
648                 av = 0;
649               else if (v >= min_v_in)
650                 av = 0;
651               else if ((out_slope != 0) && (v > min_v))
652                 av = (v - min_v ) / (min_v * 2) ;
653               else if (v > min_v_out)
654                 av = 0.5 + (v - min_v_out) / (min_v_out * 2);
655               else
656                 has_match = false;
657             }
659           // Check if the value is less than the maximum
660           if (has_match)
661             {
662               if (max_v == 0)
663                 avm = 0;
664               else if (v <= max_v_in)
665                 avm = 0;
666               else if ((out_slope != 0) && (v < max_v))
667                 avm = (v - max_v) / ( max_v * 2);
668               else if (v < max_v_out)
669                 avm = 0.5 + (v - max_v_out ) / (max_v_out *2); 
670               else
671                 has_match = false;
672             }
674           // If the color is part of the key, update the alpha channel
675           if (has_match)
676             a = MAX (MAX (ah, av), MAX (as, avm));
678           // Spill light processing       
679           if ((ABS (h - hk) < spill_threshold * 180) ||
680               ((ABS (h - hk) > 360)
681                && (ABS (h - hk) - 360 < spill_threshold * 180)))
682             {
683               s = s * spill_amount * ABS (h - hk) / (spill_threshold * 180);
685               HSV::hsv_to_rgb (r, g, b, h, s, v);
687               if (use_yuv)
688                 {
689                   /* Convert pixel to RGB float */
690                   float y = r;
691                   float u = g;
692                   float v = b;
693                   YUV::rgb_to_yuv_f (r, g, b, y, u, v);
694                   row[0] = (component_type) ((float) y * max);
695                   row[1] = (component_type) ((float) (u + 0.5) * max);
696                   row[2] = (component_type) ((float) (v + 0.5) * max);
697                 }
698               else
699                 {
700                   row[0] = (component_type) ((float) r * max);
701                   row[1] = (component_type) ((float) g * max);
702                   row[2] = (component_type) ((float) b * max);
703                 }
704               CLAMP (row[0], 0, max);
705               CLAMP (row[1], 0, max);
706               CLAMP (row[2], 0, max);
707             }
709           a += alpha_offset;
710           CLAMP (a, 0.0, 1.0);
712           if (plugin->config.show_mask)
713             {
715               if (use_yuv)
716                 {
717                   row[0] = (component_type) ((float) a * max);
718                   row[1] = (component_type) ((float) max / 2);
719                   row[2] = (component_type) ((float) max / 2);
720                 }
721               else
722                 {
723                   row[0] = (component_type) ((float) a * max);
724                   row[1] = (component_type) ((float) a * max);
725                   row[2] = (component_type) ((float) a * max);
726                 }
727             }
729           /* Multiply alpha and put back in frame */
730           if (components == 4)
731             {
732               row[3] = MIN ((component_type) (a * max), row[3]);
733             }
734           else if (use_yuv)
735             {
736               row[0] = (component_type) ((float) a * row[0]);
737               row[1] =
738                 (component_type) ((float) a * (row[1] - (max / 2 + 1)) +
739                                   max / 2 + 1);
740               row[2] =
741                 (component_type) ((float) a * (row[2] - (max / 2 + 1)) +
742                                   max / 2 + 1);
743             }
744           else
745             {
746               row[0] = (component_type) ((float) a * row[0]);
747               row[1] = (component_type) ((float) a * row[1]);
748               row[2] = (component_type) ((float) a * row[2]);
749             }
751           row += components;
752         }
753     }
759 void
760 ChromaKeyUnit::process_package (LoadPackage * package)
762   ChromaKeyPackage *pkg = (ChromaKeyPackage *) package;
765   switch (plugin->input->get_color_model ())
766     {
767     case BC_RGB_FLOAT:
768       process_chromakey < float >(3, 1.0, 0, pkg);
769       break;
770     case BC_RGBA_FLOAT:
771       process_chromakey < float >(4, 1.0, 0, pkg);
772       break;
773     case BC_RGB888:
774       process_chromakey < unsigned char >(3, 0xff, 0, pkg);
775       break;
776     case BC_RGBA8888:
777       process_chromakey < unsigned char >(4, 0xff, 0, pkg);
778       break;
779     case BC_YUV888:
780       process_chromakey < unsigned char >(3, 0xff, 1, pkg);
781       break;
782     case BC_YUVA8888:
783       process_chromakey < unsigned char >(4, 0xff, 1, pkg);
784       break;
785     case BC_YUV161616:
786       process_chromakey < uint16_t > (3, 0xffff, 1, pkg);
787       break;
788     case BC_YUVA16161616:
789       process_chromakey < uint16_t > (4, 0xffff, 1, pkg);
790       break;
791     }
799 REGISTER_PLUGIN (ChromaKey) ChromaKey::ChromaKey (PluginServer * server):PluginVClient
800   (server)
802   PLUGIN_CONSTRUCTOR_MACRO engine = 0;
805 ChromaKey::~ChromaKey ()
807   PLUGIN_DESTRUCTOR_MACRO if (engine)
808     delete engine;
813 ChromaKey::process_realtime (VFrame * input, VFrame * output)
815   load_configuration ();
816   this->input = input;
817   this->output = output;
819   if (EQUIV (config.tolerance, 0))
820     {
821       if (input->get_rows ()[0] != output->get_rows ()[0])
822         output->copy_from (input);
823     }
824   else
825     {
826       if (!engine)
827         engine = new ChromaKeyServer (this);
828       engine->process_packages ();
829     }
831   return 0;
834 char *
835 ChromaKey::plugin_title ()
837   return N_("Chroma key (HSV)");
841 ChromaKey::is_realtime ()
843   return 1;
846 NEW_PICON_MACRO (ChromaKey)
847 LOAD_CONFIGURATION_MACRO (ChromaKey, ChromaKeyConfig)
848      int ChromaKey::load_defaults ()
850   char directory[BCTEXTLEN];
851 // set the default directory
852   sprintf (directory, "%schromakey-hsv.rc", BCASTDIR);
854 // load the defaults
855   defaults = new Defaults (directory);
856   defaults->load ();
858   config.red = defaults->get ("RED", config.red);
859   config.green = defaults->get ("GREEN", config.green);
860   config.blue = defaults->get ("BLUE", config.blue);
861   config.min_brightness =
862     defaults->get ("MIN_BRIGHTNESS", config.min_brightness);
863   config.max_brightness =
864     defaults->get ("MAX_BRIGHTNESS", config.max_brightness);
865   config.saturation = defaults->get ("SATURATION", config.saturation);
866   config.min_saturation =
867     defaults->get ("MIN_SATURATION", config.min_saturation);
868   config.tolerance = defaults->get ("TOLERANCE", config.tolerance);
869   config.spill_threshold =
870     defaults->get ("SPILL_THRESHOLD", config.spill_threshold);
871   config.spill_amount = defaults->get ("SPILL_AMOUNT", config.spill_amount);
872   config.in_slope = defaults->get ("IN_SLOPE", config.in_slope);
873   config.out_slope = defaults->get ("OUT_SLOPE", config.out_slope);
874   config.alpha_offset = defaults->get ("ALPHA_OFFSET", config.alpha_offset);
875   config.show_mask = defaults->get ("SHOW_MASK", config.show_mask);
876   return 0;
880 ChromaKey::save_defaults ()
882   defaults->update ("RED", config.red);
883   defaults->update ("GREEN", config.green);
884   defaults->update ("BLUE", config.blue);
885   defaults->update ("MIN_BRIGHTNESS", config.min_brightness);
886   defaults->update ("MAX_BRIGHTNESS", config.max_brightness);
887   defaults->update ("SATURATION", config.saturation);
888   defaults->update ("MIN_SATURATION", config.min_saturation);
889   defaults->update ("TOLERANCE", config.tolerance);
890   defaults->update ("IN_SLOPE", config.in_slope);
891   defaults->update ("OUT_SLOPE", config.out_slope);
892   defaults->update ("ALPHA_OFFSET", config.alpha_offset);
893   defaults->update ("SPILL_THRESHOLD", config.spill_threshold);
894   defaults->update ("SPILL_AMOUNT", config.spill_amount);
895   defaults->update ("SHOW_MASK", config.show_mask);
896   defaults->save ();
897   return 0;
900 void
901 ChromaKey::save_data (KeyFrame * keyframe)
903   FileXML output;
904   output.set_shared_string (keyframe->data, MESSAGESIZE);
905   output.tag.set_title ("CHROMAKEY_HSV");
906   output.tag.set_property ("RED", config.red);
907   output.tag.set_property ("GREEN", config.green);
908   output.tag.set_property ("BLUE", config.blue);
909   output.tag.set_property ("MIN_BRIGHTNESS", config.min_brightness);
910   output.tag.set_property ("MAX_BRIGHTNESS", config.max_brightness);
911   output.tag.set_property ("SATURATION", config.saturation);
912   output.tag.set_property ("MIN_SATURATION", config.min_saturation);
913   output.tag.set_property ("TOLERANCE", config.tolerance);
914   output.tag.set_property ("IN_SLOPE", config.in_slope);
915   output.tag.set_property ("OUT_SLOPE", config.out_slope);
916   output.tag.set_property ("ALPHA_OFFSET", config.alpha_offset);
917   output.tag.set_property ("SPILL_THRESHOLD", config.spill_threshold);
918   output.tag.set_property ("SPILL_AMOUNT", config.spill_amount);
919   output.tag.set_property ("SHOW_MASK", config.show_mask);
920   output.append_tag ();
921   output.terminate_string ();
924 void
925 ChromaKey::read_data (KeyFrame * keyframe)
927   FileXML input;
929   input.set_shared_string (keyframe->data, strlen (keyframe->data));
931   while (!input.read_tag ())
932     {
933       if (input.tag.title_is ("CHROMAKEY_HSV"))
934         {
935           config.red = input.tag.get_property ("RED", config.red);
936           config.green = input.tag.get_property ("GREEN", config.green);
937           config.blue = input.tag.get_property ("BLUE", config.blue);
938           config.min_brightness =
939             input.tag.get_property ("MIN_BRIGHTNESS", config.min_brightness);
940           config.max_brightness =
941             input.tag.get_property ("MAX_BRIGHTNESS", config.max_brightness);
942           config.saturation =
943             input.tag.get_property ("SATURATION", config.saturation);
944           config.min_saturation =
945             input.tag.get_property ("MIN_SATURATION", config.min_saturation);
946           config.tolerance =
947             input.tag.get_property ("TOLERANCE", config.tolerance);
948           config.in_slope =
949             input.tag.get_property ("IN_SLOPE", config.in_slope);
950           config.out_slope =
951             input.tag.get_property ("OUT_SLOPE", config.out_slope);
952           config.alpha_offset =
953             input.tag.get_property ("ALPHA_OFFSET", config.alpha_offset);
954           config.spill_threshold =
955             input.tag.get_property ("SPILL_THRESHOLD",
956                                     config.spill_threshold);
957           config.spill_amount =
958             input.tag.get_property ("SPILL_AMOUNT", config.spill_amount);
959           config.show_mask =
960             input.tag.get_property ("SHOW_MASK", config.show_mask);
961         }
962     }
966 SHOW_GUI_MACRO (ChromaKey, ChromaKeyThread)
967 SET_STRING_MACRO (ChromaKey) RAISE_WINDOW_MACRO (ChromaKey)
968      void
969      ChromaKey::update_gui ()
971   if (thread)
972     {
973       load_configuration ();
974       thread->window->lock_window ();
975       thread->window->min_brightness->update (config.min_brightness);
976       thread->window->max_brightness->update (config.max_brightness);
977       thread->window->saturation->update (config.saturation);
978       thread->window->min_saturation->update (config.min_saturation);
979       thread->window->tolerance->update (config.tolerance);
980       thread->window->in_slope->update (config.in_slope);
981       thread->window->out_slope->update (config.out_slope);
982       thread->window->alpha_offset->update (config.alpha_offset);
983       thread->window->spill_threshold->update (config.spill_threshold);
984       thread->window->spill_amount->update (config.spill_amount);
985       thread->window->show_mask->update (config.show_mask);
986       thread->window->update_sample ();
987       thread->window->unlock_window ();
988     }