4 #include "bcdisplayinfo.h"
10 #include "loadbalance.h"
11 #include "plugincolors.h"
12 #include "pluginvclient.h"
28 void copy_from(DiffKeyConfig &src);
29 int equivalent(DiffKeyConfig &src);
30 void interpolate(DiffKeyConfig &prev,
34 int64_t current_frame);
42 class DiffKeyThreshold : public BC_FSlider
45 DiffKeyThreshold(DiffKey *plugin, int x, int y);
50 class DiffKeySlope : public BC_FSlider
53 DiffKeySlope(DiffKey *plugin, int x, int y);
58 class DiffKeyDoValue : public BC_CheckBox
61 DiffKeyDoValue(DiffKey *plugin, int x, int y);
68 class DiffKeyGUI : public BC_Window
71 DiffKeyGUI(DiffKey *plugin, int x, int y);
75 void create_objects();
79 DiffKeyThreshold *threshold;
81 DiffKeyDoValue *do_value;
86 PLUGIN_THREAD_HEADER(DiffKey, DiffKeyThread, DiffKeyGUI)
90 class DiffKeyEngine : public LoadServer
93 DiffKeyEngine(DiffKey *plugin);
95 LoadClient* new_client();
96 LoadPackage* new_package();
101 class DiffKeyClient : public LoadClient
104 DiffKeyClient(DiffKeyEngine *engine);
107 void process_package(LoadPackage *pkg);
108 DiffKeyEngine *engine;
111 class DiffKeyPackage : public LoadPackage
121 class DiffKey : public PluginVClient
124 DiffKey(PluginServer *server);
127 int process_buffer(VFrame **frame,
128 int64_t start_position,
131 int is_multichannel();
134 void save_data(KeyFrame *keyframe);
135 void read_data(KeyFrame *keyframe);
140 PLUGIN_CLASS_MEMBERS(DiffKeyConfig, DiffKeyThread)
142 DiffKeyEngine *engine;
144 VFrame *bottom_frame;
154 REGISTER_PLUGIN(DiffKey)
157 DiffKeyConfig::DiffKeyConfig()
164 void DiffKeyConfig::copy_from(DiffKeyConfig &src)
166 this->threshold = src.threshold;
167 this->slope = src.slope;
168 this->do_value = src.do_value;
172 int DiffKeyConfig::equivalent(DiffKeyConfig &src)
174 return EQUIV(threshold, src.threshold) &&
175 EQUIV(slope, src.slope) &&
176 do_value == src.do_value;
179 void DiffKeyConfig::interpolate(DiffKeyConfig &prev,
183 int64_t current_frame)
185 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
186 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
188 this->threshold = prev.threshold * prev_scale + next.threshold * next_scale;
189 this->slope = prev.slope * prev_scale + next.slope * next_scale;
190 this->do_value = prev.do_value;
202 DiffKeyThreshold::DiffKeyThreshold(DiffKey *plugin, int x, int y)
203 : BC_FSlider(x, y, 0, 200, 200, 0, 100, plugin->config.threshold)
205 this->plugin = plugin;
208 int DiffKeyThreshold::handle_event()
210 plugin->config.threshold = get_value();
211 plugin->send_configure_change();
222 DiffKeySlope::DiffKeySlope(DiffKey *plugin, int x, int y)
223 : BC_FSlider(x, y, 0, 200, 200, 0, 100, plugin->config.slope)
225 this->plugin = plugin;
228 int DiffKeySlope::handle_event()
230 plugin->config.slope = get_value();
231 plugin->send_configure_change();
237 DiffKeyDoValue::DiffKeyDoValue(DiffKey *plugin, int x, int y)
238 : BC_CheckBox(x, y, plugin->config.do_value, _("Use Value"))
240 this->plugin = plugin;
243 int DiffKeyDoValue::handle_event()
245 plugin->config.do_value = get_value();
246 plugin->send_configure_change();
256 DiffKeyGUI::DiffKeyGUI(DiffKey *plugin, int x, int y)
257 : BC_Window(plugin->gui_string,
268 this->plugin = plugin;
271 DiffKeyGUI::~DiffKeyGUI()
276 void DiffKeyGUI::create_objects()
278 int x = 10, y = 10, x2;
280 add_subwindow(title = new BC_Title(x, y, "Threshold:"));
281 x += title->get_w() + 10;
282 add_subwindow(threshold = new DiffKeyThreshold(plugin, x, y));
284 y += threshold->get_h() + 10;
285 add_subwindow(title = new BC_Title(x, y, "Slope:"));
286 x += title->get_w() + 10;
287 add_subwindow(slope = new DiffKeySlope(plugin, x, y));
289 y += slope->get_h() + 10;
290 add_subwindow(do_value = new DiffKeyDoValue(plugin, x, y));
297 WINDOW_CLOSE_EVENT(DiffKeyGUI)
300 PLUGIN_THREAD_OBJECT(DiffKey, DiffKeyThread, DiffKeyGUI)
304 DiffKey::DiffKey(PluginServer *server)
305 : PluginVClient(server)
307 PLUGIN_CONSTRUCTOR_MACRO
313 PLUGIN_DESTRUCTOR_MACRO
317 SHOW_GUI_MACRO(DiffKey, DiffKeyThread)
318 RAISE_WINDOW_MACRO(DiffKey)
319 SET_STRING_MACRO(DiffKey)
320 #include "picon_png.h"
321 NEW_PICON_MACRO(DiffKey)
322 LOAD_CONFIGURATION_MACRO(DiffKey, DiffKeyConfig)
324 char* DiffKey::plugin_title() { return N_("Difference key"); }
325 int DiffKey::is_realtime() { return 1; }
326 int DiffKey::is_multichannel() { return 1; }
328 int DiffKey::load_defaults()
330 char directory[BCTEXTLEN];
331 // set the default directory
332 sprintf(directory, "%sdiffkey.rc", BCASTDIR);
335 defaults = new Defaults(directory);
338 config.threshold = defaults->get("THRESHOLD", config.threshold);
339 config.slope = defaults->get("SLOPE", config.slope);
340 config.do_value = defaults->get("DO_VALUE", config.do_value);
344 int DiffKey::save_defaults()
346 defaults->update("THRESHOLD", config.threshold);
347 defaults->update("SLOPE", config.slope);
348 defaults->update("DO_VALUE", config.do_value);
353 void DiffKey::save_data(KeyFrame *keyframe)
356 output.set_shared_string(keyframe->data, MESSAGESIZE);
357 output.tag.set_title("DIFFKEY");
358 output.tag.set_property("THRESHOLD", config.threshold);
359 output.tag.set_property("SLOPE", config.slope);
360 output.tag.set_property("DO_VALUE", config.do_value);
362 output.terminate_string();
365 void DiffKey::read_data(KeyFrame *keyframe)
369 input.set_shared_string(keyframe->data, strlen(keyframe->data));
371 while(!input.read_tag())
373 if(input.tag.title_is("DIFFKEY"))
375 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
376 config.slope = input.tag.get_property("SLOPE", config.slope);
377 config.do_value = input.tag.get_property("DO_VALUE", config.do_value);
382 void DiffKey::update_gui()
386 if(load_configuration())
388 thread->window->lock_window("DiffKey::update_gui");
389 thread->window->threshold->update(config.threshold);
390 thread->window->slope->update(config.slope);
391 thread->window->do_value->update(config.do_value);
392 thread->window->unlock_window();
397 int DiffKey::process_buffer(VFrame **frame,
398 int64_t start_position,
401 load_configuration();
403 // Don't process if only 1 layer.
404 if(get_total_buffers() < 2)
406 read_frame(frame[0], 0, start_position, frame_rate);
410 // Read frames from 2 layers
411 read_frame(frame[0], 0, start_position, frame_rate);
412 read_frame(frame[1], 1, start_position, frame_rate);
414 top_frame = frame[0];
415 bottom_frame = frame[1];
419 engine = new DiffKeyEngine(this);
422 engine->process_packages();
433 DiffKeyEngine::DiffKeyEngine(DiffKey *plugin)
434 : LoadServer(plugin->get_project_smp() + 1, plugin->get_project_smp() + 1)
436 this->plugin = plugin;
439 void DiffKeyEngine::init_packages()
441 int increment = plugin->top_frame->get_h() / get_total_packages() + 1;
443 for(int i = 0; i < get_total_packages(); i++)
445 DiffKeyPackage *pkg = (DiffKeyPackage*)get_package(i);
447 pkg->row2 = MIN(y + increment, plugin->top_frame->get_h());
452 LoadClient* DiffKeyEngine::new_client()
454 return new DiffKeyClient(this);
457 LoadPackage* DiffKeyEngine::new_package()
459 return new DiffKeyPackage;
472 DiffKeyClient::DiffKeyClient(DiffKeyEngine *engine)
475 this->engine = engine;
478 DiffKeyClient::~DiffKeyClient()
482 void DiffKeyClient::process_package(LoadPackage *ptr)
484 DiffKeyPackage *pkg = (DiffKeyPackage*)ptr;
485 DiffKey *plugin = engine->plugin;
486 int w = plugin->top_frame->get_w();
488 #define RGB_TO_VALUE(r, g, b) \
489 ((r) * R_TO_Y + (g) * G_TO_Y + (b) * B_TO_Y)
491 #define SQR(x) ((x) * (x))
493 #define DIFFKEY_MACRO(type, components, max, chroma_offset) \
495 float threshold = plugin->config.threshold / 100; \
496 float run = plugin->config.slope / 100; \
497 float threshold_run = threshold + run; \
499 for(int i = pkg->row1; i < pkg->row2; i++) \
501 type *top_row = (type*)plugin->top_frame->get_rows()[i]; \
502 type *bottom_row = (type*)plugin->bottom_frame->get_rows()[i]; \
504 for(int j = 0; j < w; j++) \
508 /* Test for value in range */ \
509 if(plugin->config.do_value) \
512 float bottom_value; \
514 /* Convert pixel data into floating point value */ \
517 float top_r = (float)top_row[0] / max; \
518 float bottom_r = (float)bottom_row[0] / max; \
520 bottom_value = bottom_r; \
524 float top_r = (float)top_row[0] / max; \
525 float top_g = (float)top_row[1] / max; \
526 float top_b = (float)top_row[2] / max; \
527 top_g -= (float)chroma_offset / max; \
528 top_b -= (float)chroma_offset / max; \
530 float bottom_r = (float)bottom_row[0] / max; \
531 float bottom_g = (float)bottom_row[1] / max; \
532 float bottom_b = (float)bottom_row[2] / max; \
533 bottom_g -= (float)chroma_offset / max; \
534 bottom_b -= (float)chroma_offset / max; \
536 top_value = RGB_TO_VALUE(top_r, top_g, top_b); \
537 bottom_value = RGB_TO_VALUE(bottom_r, bottom_g, bottom_b); \
540 float min_v = bottom_value - threshold; \
541 float max_v = bottom_value + threshold; \
543 /* Full transparency if in range */ \
544 if(top_value >= min_v && top_value < max_v) \
549 /* Phased out if below or above range */ \
550 if(top_value < min_v) \
552 if(min_v - top_value < run) \
553 a = (min_v - top_value) / run; \
556 if(top_value - max_v < run) \
557 a = (top_value - max_v) / run; \
560 /* Use color cube */ \
562 float top_r = (float)top_row[0] / max; \
563 float top_g = (float)top_row[1] / max; \
564 float top_b = (float)top_row[2] / max; \
565 top_g -= (float)chroma_offset / max; \
566 top_b -= (float)chroma_offset / max; \
568 float bottom_r = (float)bottom_row[0] / max; \
569 float bottom_g = (float)bottom_row[1] / max; \
570 float bottom_b = (float)bottom_row[2] / max; \
571 bottom_g -= (float)chroma_offset / max; \
572 bottom_b -= (float)chroma_offset / max; \
574 /* Convert pixel values to RGB float */ \
577 float y = bottom_r; \
578 float u = bottom_g; \
579 float v = bottom_b; \
580 YUV::yuv_to_rgb_f(bottom_r, \
589 YUV::yuv_to_rgb_f(top_r, \
597 float difference = sqrt(SQR(top_r - bottom_r) + \
598 SQR(top_g - bottom_g) + \
599 SQR(top_b - bottom_b)); \
601 if(difference < threshold) \
606 if(difference < threshold_run) \
608 a = (difference - threshold) / run; \
612 /* multiply alpha */ \
613 if(components == 4) \
615 top_row[3] = MIN((type)(a * max), top_row[3]); \
619 top_row[0] = (type)(a * top_row[0]); \
620 top_row[1] = (type)(a * (top_row[1] - chroma_offset) + chroma_offset); \
621 top_row[2] = (type)(a * (top_row[2] - chroma_offset) + chroma_offset); \
624 top_row += components; \
625 bottom_row += components; \
632 switch(plugin->top_frame->get_color_model())
635 DIFFKEY_MACRO(float, 3, 1.0, 0);
638 DIFFKEY_MACRO(float, 4, 1.0, 0);
641 DIFFKEY_MACRO(unsigned char, 3, 0xff, 0);
644 DIFFKEY_MACRO(unsigned char, 4, 0xff, 0);
647 DIFFKEY_MACRO(unsigned char, 3, 0xff, 0x80);
650 DIFFKEY_MACRO(unsigned char, 4, 0xff, 0x80);
661 DiffKeyPackage::DiffKeyPackage()