1 #include "bcdisplayinfo.h"
8 #include "loadbalance.h"
10 #include "plugincolors.h"
11 #include "pluginvclient.h"
18 #define _(String) gettext(String)
19 #define gettext_noop(String) String
20 #define N_(String) gettext_noop (String)
25 ChromaKeyConfig::ChromaKeyConfig()
35 void ChromaKeyConfig::copy_from(ChromaKeyConfig &src)
38 threshold = src.threshold;
40 use_value = src.use_value;
44 int ChromaKeyConfig::equivalent(ChromaKeyConfig &src)
46 return (EQUIV(hue, src.hue) &&
47 EQUIV(threshold, src.threshold) &&
48 EQUIV(value, src.value) &&
49 EQUIV(slope, src.slope) &&
50 use_value == src.use_value);
53 void ChromaKeyConfig::interpolate(ChromaKeyConfig &prev,
54 ChromaKeyConfig &next,
57 int64_t current_frame)
59 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
60 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
62 this->hue = prev.hue * prev_scale + next.hue * next_scale;
63 this->threshold = prev.threshold * prev_scale + next.threshold * next_scale;
64 this->value = prev.value * prev_scale + next.value * next_scale;
65 this->use_value = prev.use_value;
66 this->slope = prev.slope * prev_scale + next.slope * next_scale;
70 ChromaKeyWindow::ChromaKeyWindow(ChromaKey *plugin, int x, int y)
71 : BC_Window(plugin->gui_string,
82 this->plugin = plugin;
85 ChromaKeyWindow::~ChromaKeyWindow()
89 void ChromaKeyWindow::create_objects()
91 int x = 10, y = 10, x1 = 100;
93 for(int i = 0; i < 200; i++)
96 HSV::hsv_to_rgb(r, g, b, i * 360 / 200, 1, 1);
97 int color = (((int)(r * 0xff)) << 16) | (((int)(g * 0xff)) << 8) | ((int)(b * 0xff));
99 draw_line(x1 + i, y, x1 + i, y + 25);
102 add_subwindow(new BC_Title(x, y, _("Hue:")));
103 add_subwindow(hue = new ChromaKeyHue(plugin, x1, y));
106 for(int i = 0; i < 200; i++)
108 int r = i * 0xff / 200;
109 set_color((r << 16) | (r << 8) | r);
110 draw_line(x1 + i, y, x1 + i, y + 25);
114 add_subwindow(new BC_Title(x, y, _("Value:")));
115 add_subwindow(value = new ChromaKeyValue(plugin, x1, y));
118 add_subwindow(new BC_Title(x, y, _("Slope:")));
119 add_subwindow(slope = new ChromaKeySlope(plugin, x1, y));
122 add_subwindow(new BC_Title(x, y, _("Threshold:")));
123 add_subwindow(threshold = new ChromaKeyThreshold(plugin, x1, y));
127 add_subwindow(use_value = new ChromaKeyUseValue(plugin, x1, y));
133 int ChromaKeyWindow::close_event()
139 ChromaKeyHue::ChromaKeyHue(ChromaKey *plugin, int x, int y)
149 this->plugin = plugin;
152 int ChromaKeyHue::handle_event()
154 plugin->config.hue = get_value();
155 plugin->send_configure_change();
159 ChromaKeyThreshold::ChromaKeyThreshold(ChromaKey *plugin, int x, int y)
167 plugin->config.threshold)
169 this->plugin = plugin;
172 int ChromaKeyThreshold::handle_event()
174 plugin->config.threshold = get_value();
175 plugin->send_configure_change();
179 ChromaKeyValue::ChromaKeyValue(ChromaKey *plugin, int x, int y)
187 plugin->config.value)
189 this->plugin = plugin;
192 int ChromaKeyValue::handle_event()
194 plugin->config.value = get_value();
195 plugin->send_configure_change();
201 ChromaKeySlope::ChromaKeySlope(ChromaKey *plugin, int x, int y)
209 plugin->config.slope)
211 this->plugin = plugin;
214 int ChromaKeySlope::handle_event()
216 plugin->config.slope = get_value();
217 plugin->send_configure_change();
222 ChromaKeyUseValue::ChromaKeyUseValue(ChromaKey *plugin, int x, int y)
223 : BC_CheckBox(x, y, plugin->config.use_value, _("Use value"))
225 this->plugin = plugin;
227 int ChromaKeyUseValue::handle_event()
229 plugin->config.use_value = get_value();
230 plugin->send_configure_change();
242 PLUGIN_THREAD_OBJECT(ChromaKey, ChromaKeyThread, ChromaKeyWindow)
245 ChromaKeyServer::ChromaKeyServer(ChromaKey *plugin)
246 : LoadServer(plugin->PluginClient::smp + 1, plugin->PluginClient::smp + 1)
248 this->plugin = plugin;
250 void ChromaKeyServer::init_packages()
252 int increment = plugin->input->get_h() / get_total_packages() + 1;
254 for(int i = 0; i < get_total_packages(); i++)
256 ChromaKeyPackage *pkg = (ChromaKeyPackage*)get_package(i);
258 pkg->y2 = y + increment;
260 if(pkg->y2 > plugin->input->get_h())
262 y = pkg->y2 = plugin->input->get_h();
264 if(pkg->y1 > plugin->input->get_h())
266 y = pkg->y1 = plugin->input->get_h();
271 LoadClient* ChromaKeyServer::new_client()
273 return new ChromaKeyUnit(plugin, this);
275 LoadPackage* ChromaKeyServer::new_package()
277 return new ChromaKeyPackage();
282 ChromaKeyPackage::ChromaKeyPackage()
287 ChromaKeyUnit::ChromaKeyUnit(ChromaKey *plugin, ChromaKeyServer *server)
290 this->plugin = plugin;
292 void ChromaKeyUnit::process_package(LoadPackage *package)
294 ChromaKeyPackage *pkg = (ChromaKeyPackage*)package;
296 int w = plugin->input->get_w();
297 float min_h = plugin->config.hue - plugin->config.threshold * 3.60 / 2;
298 float max_h = plugin->config.hue + plugin->config.threshold * 3.60 / 2;
299 float min_v = (plugin->config.value - plugin->config.threshold / 2) / 100;
300 float max_v = (plugin->config.value + plugin->config.threshold / 2) / 100;
304 if(plugin->config.use_value)
305 run = (max_v - min_v) / 2 * (1 - plugin->config.slope / 100);
307 run = (max_h - min_h) / 2 * (1 - plugin->config.slope / 100);
309 // printf("ChromaKeyUnit::process_package %f %f %f %f\n",
310 // min_h, max_h, min_v, max_v);
312 #define CHROMAKEY(type, max, components, use_yuv) \
316 chroma_offset = max / 2 + 1; \
319 for(int i = pkg->y1; i < pkg->y2; i++) \
322 type *row = (type*)plugin->input->get_rows()[i]; \
324 for(int j = 0; j < w; j++) \
328 HSV::yuv_to_hsv(row[0], \
338 HSV::rgb_to_hsv((float)row[0] / max, \
339 (float)row[1] / max, \
340 (float)row[2] / max, \
344 if(plugin->config.use_value) \
346 if(va >= min_v && va <= max_v) \
348 if(va - min_v < max_v - va) \
350 if(va - min_v < run) \
351 a = (int)(max - (va - min_v) / run * max); \
357 if(max_v - va < run) \
358 a = (int)(max - (max_v - va) / run * max); \
363 if(components == 4) \
364 row[3] = MIN(a, row[3]); \
367 row[0] = (a * row[0]) / max; \
368 row[1] = (a * row[1] + (max - a) * chroma_offset) / max; \
369 row[2] = (a * row[2] + (max - a) * chroma_offset) / max; \
375 if(h >= min_h && h <= max_h) \
377 if(h - min_h < max_h - h) \
379 if(h - min_h < run) \
380 a = (int)(max - (h - min_h) / run * max); \
386 if(max_h - h < run) \
387 a = (int)(max - (max_h - h) / run * max); \
392 if(components == 4) \
393 row[3] = MIN(a, row[3]); \
396 row[0] = a * row[0] / max; \
397 row[1] = (a * row[1] + (max - a) * chroma_offset) / max; \
398 row[2] = (a * row[2] + (max - a) * chroma_offset) / max; \
411 switch(plugin->input->get_color_model())
414 CHROMAKEY(unsigned char, 0xff, 3, 0);
417 CHROMAKEY(unsigned char, 0xff, 3, 1);
420 CHROMAKEY(unsigned char, 0xff, 4, 0);
423 CHROMAKEY(unsigned char, 0xff, 4, 1);
426 CHROMAKEY(uint16_t, 0xffff, 3, 0);
429 CHROMAKEY(uint16_t, 0xffff, 3, 1);
431 case BC_RGBA16161616:
432 CHROMAKEY(uint16_t, 0xffff, 4, 0);
434 case BC_YUVA16161616:
435 CHROMAKEY(uint16_t, 0xffff, 4, 1);
445 REGISTER_PLUGIN(ChromaKey)
449 ChromaKey::ChromaKey(PluginServer *server)
450 : PluginVClient(server)
452 PLUGIN_CONSTRUCTOR_MACRO
456 ChromaKey::~ChromaKey()
458 PLUGIN_DESTRUCTOR_MACRO
459 if(engine) delete engine;
463 int ChromaKey::process_realtime(VFrame *input, VFrame *output)
465 load_configuration();
467 this->output = output;
469 if(EQUIV(config.threshold, 0))
471 if(input->get_rows()[0] != output->get_rows()[0])
472 output->copy_from(input);
476 if(!engine) engine = new ChromaKeyServer(this);
477 engine->process_packages();
483 int ChromaKey::is_realtime()
487 char* ChromaKey::plugin_title()
489 return _("Chroma key");
492 NEW_PICON_MACRO(ChromaKey)
494 LOAD_CONFIGURATION_MACRO(ChromaKey, ChromaKeyConfig)
496 int ChromaKey::load_defaults()
498 char directory[BCTEXTLEN];
499 // set the default directory
500 sprintf(directory, "%schromakey.rc", BCASTDIR);
503 defaults = new Defaults(directory);
506 config.hue = defaults->get("HUE", config.hue);
507 config.value = defaults->get("VALUE", config.value);
508 config.threshold = defaults->get("THRESHOLD", config.threshold);
509 config.threshold = defaults->get("SLOPE", config.slope);
510 config.use_value = defaults->get("USE_VALUE", config.use_value);
514 int ChromaKey::save_defaults()
516 defaults->update("HUE", config.hue);
517 defaults->update("VALUE", config.value);
518 defaults->update("THRESHOLD", config.threshold);
519 defaults->update("SLOPE", config.slope);
520 defaults->update("USE_VALUE", config.use_value);
525 void ChromaKey::save_data(KeyFrame *keyframe)
528 output.set_shared_string(keyframe->data, MESSAGESIZE);
529 output.tag.set_title("CHROMAKEY");
530 output.tag.set_property("HUE", config.hue);
531 output.tag.set_property("VALUE", config.value);
532 output.tag.set_property("THRESHOLD", config.threshold);
533 output.tag.set_property("SLOPE", config.slope);
534 output.tag.set_property("USE_VALUE", config.use_value);
536 output.terminate_string();
539 void ChromaKey::read_data(KeyFrame *keyframe)
543 input.set_shared_string(keyframe->data, strlen(keyframe->data));
545 while(!input.read_tag())
547 if(input.tag.title_is("CHROMAKEY"))
549 config.hue = input.tag.get_property("HUE", config.hue);
550 config.value = input.tag.get_property("VALUE", config.value);
551 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
552 config.slope = input.tag.get_property("SLOPE", config.slope);
553 config.use_value = input.tag.get_property("USE_VALUE", config.use_value);
559 SHOW_GUI_MACRO(ChromaKey, ChromaKeyThread)
561 SET_STRING_MACRO(ChromaKey)
563 RAISE_WINDOW_MACRO(ChromaKey)
565 void ChromaKey::update_gui()
569 load_configuration();
570 thread->window->lock_window();
571 thread->window->hue->update(config.hue);
572 thread->window->value->update(config.value);
573 thread->window->threshold->update(config.threshold);
574 thread->window->slope->update(config.slope);
575 thread->window->use_value->update(config.use_value);
576 thread->window->unlock_window();