1 #include "bcdisplayinfo.h"
9 #include "loadbalance.h"
10 #include "picon_png.h"
11 #include "plugincolors.h"
12 #include "pluginvclient.h"
22 ChromaKeyConfig::ChromaKeyConfig()
32 void ChromaKeyConfig::copy_from(ChromaKeyConfig &src)
35 threshold = src.threshold;
37 use_value = src.use_value;
41 int ChromaKeyConfig::equivalent(ChromaKeyConfig &src)
43 return (EQUIV(hue, src.hue) &&
44 EQUIV(threshold, src.threshold) &&
45 EQUIV(value, src.value) &&
46 EQUIV(slope, src.slope) &&
47 use_value == src.use_value);
50 void ChromaKeyConfig::interpolate(ChromaKeyConfig &prev,
51 ChromaKeyConfig &next,
54 int64_t current_frame)
56 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
57 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
59 this->hue = prev.hue * prev_scale + next.hue * next_scale;
60 this->threshold = prev.threshold * prev_scale + next.threshold * next_scale;
61 this->value = prev.value * prev_scale + next.value * next_scale;
62 this->use_value = prev.use_value;
63 this->slope = prev.slope * prev_scale + next.slope * next_scale;
67 ChromaKeyWindow::ChromaKeyWindow(ChromaKey *plugin, int x, int y)
68 : BC_Window(plugin->gui_string,
79 this->plugin = plugin;
82 ChromaKeyWindow::~ChromaKeyWindow()
86 void ChromaKeyWindow::create_objects()
88 int x = 10, y = 10, x1 = 100;
90 for(int i = 0; i < 200; i++)
93 HSV::hsv_to_rgb(r, g, b, i * 360 / 200, 1, 1);
94 int color = (((int)(r * 0xff)) << 16) | (((int)(g * 0xff)) << 8) | ((int)(b * 0xff));
96 draw_line(x1 + i, y, x1 + i, y + 25);
99 add_subwindow(new BC_Title(x, y, _("Hue:")));
100 add_subwindow(hue = new ChromaKeyHue(plugin, x1, y));
103 for(int i = 0; i < 200; i++)
105 int r = i * 0xff / 200;
106 set_color((r << 16) | (r << 8) | r);
107 draw_line(x1 + i, y, x1 + i, y + 25);
111 add_subwindow(new BC_Title(x, y, _("Value:")));
112 add_subwindow(value = new ChromaKeyValue(plugin, x1, y));
115 add_subwindow(new BC_Title(x, y, _("Slope:")));
116 add_subwindow(slope = new ChromaKeySlope(plugin, x1, y));
119 add_subwindow(new BC_Title(x, y, _("Threshold:")));
120 add_subwindow(threshold = new ChromaKeyThreshold(plugin, x1, y));
124 add_subwindow(use_value = new ChromaKeyUseValue(plugin, x1, y));
130 int ChromaKeyWindow::close_event()
136 ChromaKeyHue::ChromaKeyHue(ChromaKey *plugin, int x, int y)
146 this->plugin = plugin;
149 int ChromaKeyHue::handle_event()
151 plugin->config.hue = get_value();
152 plugin->send_configure_change();
156 ChromaKeyThreshold::ChromaKeyThreshold(ChromaKey *plugin, int x, int y)
164 plugin->config.threshold)
166 this->plugin = plugin;
169 int ChromaKeyThreshold::handle_event()
171 plugin->config.threshold = get_value();
172 plugin->send_configure_change();
176 ChromaKeyValue::ChromaKeyValue(ChromaKey *plugin, int x, int y)
184 plugin->config.value)
186 this->plugin = plugin;
189 int ChromaKeyValue::handle_event()
191 plugin->config.value = get_value();
192 plugin->send_configure_change();
198 ChromaKeySlope::ChromaKeySlope(ChromaKey *plugin, int x, int y)
206 plugin->config.slope)
208 this->plugin = plugin;
211 int ChromaKeySlope::handle_event()
213 plugin->config.slope = get_value();
214 plugin->send_configure_change();
219 ChromaKeyUseValue::ChromaKeyUseValue(ChromaKey *plugin, int x, int y)
220 : BC_CheckBox(x, y, plugin->config.use_value, _("Use value"))
222 this->plugin = plugin;
224 int ChromaKeyUseValue::handle_event()
226 plugin->config.use_value = get_value();
227 plugin->send_configure_change();
239 PLUGIN_THREAD_OBJECT(ChromaKey, ChromaKeyThread, ChromaKeyWindow)
242 ChromaKeyServer::ChromaKeyServer(ChromaKey *plugin)
243 : LoadServer(plugin->PluginClient::smp + 1, plugin->PluginClient::smp + 1)
245 this->plugin = plugin;
247 void ChromaKeyServer::init_packages()
249 int increment = plugin->input->get_h() / get_total_packages() + 1;
251 for(int i = 0; i < get_total_packages(); i++)
253 ChromaKeyPackage *pkg = (ChromaKeyPackage*)get_package(i);
255 pkg->y2 = y + increment;
257 if(pkg->y2 > plugin->input->get_h())
259 y = pkg->y2 = plugin->input->get_h();
261 if(pkg->y1 > plugin->input->get_h())
263 y = pkg->y1 = plugin->input->get_h();
268 LoadClient* ChromaKeyServer::new_client()
270 return new ChromaKeyUnit(plugin, this);
272 LoadPackage* ChromaKeyServer::new_package()
274 return new ChromaKeyPackage();
279 ChromaKeyPackage::ChromaKeyPackage()
284 ChromaKeyUnit::ChromaKeyUnit(ChromaKey *plugin, ChromaKeyServer *server)
287 this->plugin = plugin;
289 void ChromaKeyUnit::process_package(LoadPackage *package)
291 ChromaKeyPackage *pkg = (ChromaKeyPackage*)package;
293 int w = plugin->input->get_w();
294 float min_h = plugin->config.hue - plugin->config.threshold * 3.60 / 2;
295 float max_h = plugin->config.hue + plugin->config.threshold * 3.60 / 2;
296 float min_v = (plugin->config.value - plugin->config.threshold / 2) / 100;
297 float max_v = (plugin->config.value + plugin->config.threshold / 2) / 100;
300 if(plugin->config.use_value)
301 run = (max_v - min_v) / 2 * (1 - plugin->config.slope / 100);
303 run = (max_h - min_h) / 2 * (1 - plugin->config.slope / 100);
305 // printf("ChromaKeyUnit::process_package %f %f %f %f\n",
306 // min_h, max_h, min_v, max_v);
308 #define CHROMAKEY(type, temp, max, components, use_yuv) \
310 temp chroma_offset; \
314 chroma_offset = max / 2 + 1; \
317 for(int i = pkg->y1; i < pkg->y2; i++) \
320 type *row = (type*)plugin->input->get_rows()[i]; \
322 for(int j = 0; j < w; j++) \
326 HSV::yuv_to_hsv(row[0], \
336 HSV::rgb_to_hsv((float)row[0] / max, \
337 (float)row[1] / max, \
338 (float)row[2] / max, \
342 if(plugin->config.use_value) \
344 if(va >= min_v && va <= max_v) \
346 if(va - min_v < max_v - va) \
348 if(va - min_v < run) \
349 a = (temp)(max - (va - min_v) / run * max); \
355 if(max_v - va < run) \
356 a = (temp)(max - (max_v - va) / run * max); \
361 if(components == 4) \
362 row[3] = MIN(a, row[3]); \
365 row[0] = (type)((a * row[0]) / max); \
366 row[1] = (type)((a * row[1] + (max - a) * chroma_offset) / max); \
367 row[2] = (type)((a * row[2] + (max - a) * chroma_offset) / max); \
373 if(h >= min_h && h <= max_h) \
375 if(h - min_h < max_h - h) \
377 if(h - min_h < run) \
378 a = (temp)(max - (h - min_h) / run * max); \
384 if(max_h - h < run) \
385 a = (temp)(max - (max_h - h) / run * max); \
390 if(components == 4) \
391 row[3] = MIN(a, row[3]); \
394 row[0] = (type)(a * row[0] / max); \
395 row[1] = (type)((a * row[1] + (max - a) * chroma_offset) / max); \
396 row[2] = (type)((a * row[2] + (max - a) * chroma_offset) / max); \
409 switch(plugin->input->get_color_model())
412 CHROMAKEY(unsigned char, int, 0xff, 3, 0);
415 CHROMAKEY(float, float, 1.0, 3, 0);
418 CHROMAKEY(unsigned char, int, 0xff, 3, 1);
421 CHROMAKEY(unsigned char, int, 0xff, 4, 0);
424 CHROMAKEY(float, float, 1.0, 4, 0);
427 CHROMAKEY(unsigned char, int, 0xff, 4, 1);
430 CHROMAKEY(uint16_t, int, 0xffff, 3, 0);
433 CHROMAKEY(uint16_t, int, 0xffff, 3, 1);
435 case BC_RGBA16161616:
436 CHROMAKEY(uint16_t, int, 0xffff, 4, 0);
438 case BC_YUVA16161616:
439 CHROMAKEY(uint16_t, int, 0xffff, 4, 1);
449 REGISTER_PLUGIN(ChromaKey)
453 ChromaKey::ChromaKey(PluginServer *server)
454 : PluginVClient(server)
456 PLUGIN_CONSTRUCTOR_MACRO
460 ChromaKey::~ChromaKey()
462 PLUGIN_DESTRUCTOR_MACRO
463 if(engine) delete engine;
467 int ChromaKey::process_realtime(VFrame *input, VFrame *output)
469 load_configuration();
471 this->output = output;
473 if(EQUIV(config.threshold, 0))
475 if(input->get_rows()[0] != output->get_rows()[0])
476 output->copy_from(input);
480 if(!engine) engine = new ChromaKeyServer(this);
481 engine->process_packages();
487 char* ChromaKey::plugin_title() { return N_("Chroma key"); }
488 int ChromaKey::is_realtime() { return 1; }
490 NEW_PICON_MACRO(ChromaKey)
492 LOAD_CONFIGURATION_MACRO(ChromaKey, ChromaKeyConfig)
494 int ChromaKey::load_defaults()
496 char directory[BCTEXTLEN];
497 // set the default directory
498 sprintf(directory, "%schromakey.rc", BCASTDIR);
501 defaults = new Defaults(directory);
504 config.hue = defaults->get("HUE", config.hue);
505 config.value = defaults->get("VALUE", config.value);
506 config.threshold = defaults->get("THRESHOLD", config.threshold);
507 config.threshold = defaults->get("SLOPE", config.slope);
508 config.use_value = defaults->get("USE_VALUE", config.use_value);
512 int ChromaKey::save_defaults()
514 defaults->update("HUE", config.hue);
515 defaults->update("VALUE", config.value);
516 defaults->update("THRESHOLD", config.threshold);
517 defaults->update("SLOPE", config.slope);
518 defaults->update("USE_VALUE", config.use_value);
523 void ChromaKey::save_data(KeyFrame *keyframe)
526 output.set_shared_string(keyframe->data, MESSAGESIZE);
527 output.tag.set_title("CHROMAKEY");
528 output.tag.set_property("HUE", config.hue);
529 output.tag.set_property("VALUE", config.value);
530 output.tag.set_property("THRESHOLD", config.threshold);
531 output.tag.set_property("SLOPE", config.slope);
532 output.tag.set_property("USE_VALUE", config.use_value);
534 output.terminate_string();
537 void ChromaKey::read_data(KeyFrame *keyframe)
541 input.set_shared_string(keyframe->data, strlen(keyframe->data));
543 while(!input.read_tag())
545 if(input.tag.title_is("CHROMAKEY"))
547 config.hue = input.tag.get_property("HUE", config.hue);
548 config.value = input.tag.get_property("VALUE", config.value);
549 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
550 config.slope = input.tag.get_property("SLOPE", config.slope);
551 config.use_value = input.tag.get_property("USE_VALUE", config.use_value);
557 SHOW_GUI_MACRO(ChromaKey, ChromaKeyThread)
559 SET_STRING_MACRO(ChromaKey)
561 RAISE_WINDOW_MACRO(ChromaKey)
563 void ChromaKey::update_gui()
567 load_configuration();
568 thread->window->lock_window();
569 thread->window->hue->update(config.hue);
570 thread->window->value->update(config.value);
571 thread->window->threshold->update(config.threshold);
572 thread->window->slope->update(config.slope);
573 thread->window->use_value->update(config.use_value);
574 thread->window->unlock_window();