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);
141 PLUGIN_CLASS_MEMBERS(DiffKeyConfig, DiffKeyThread)
143 DiffKeyEngine *engine;
145 VFrame *bottom_frame;
155 REGISTER_PLUGIN(DiffKey)
158 DiffKeyConfig::DiffKeyConfig()
165 void DiffKeyConfig::copy_from(DiffKeyConfig &src)
167 this->threshold = src.threshold;
168 this->slope = src.slope;
169 this->do_value = src.do_value;
173 int DiffKeyConfig::equivalent(DiffKeyConfig &src)
175 return EQUIV(threshold, src.threshold) &&
176 EQUIV(slope, src.slope) &&
177 do_value == src.do_value;
180 void DiffKeyConfig::interpolate(DiffKeyConfig &prev,
184 int64_t current_frame)
186 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
187 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
189 this->threshold = prev.threshold * prev_scale + next.threshold * next_scale;
190 this->slope = prev.slope * prev_scale + next.slope * next_scale;
191 this->do_value = prev.do_value;
203 DiffKeyThreshold::DiffKeyThreshold(DiffKey *plugin, int x, int y)
204 : BC_FSlider(x, y, 0, 200, 200, 0, 100, plugin->config.threshold)
206 this->plugin = plugin;
209 int DiffKeyThreshold::handle_event()
211 plugin->config.threshold = get_value();
212 plugin->send_configure_change();
223 DiffKeySlope::DiffKeySlope(DiffKey *plugin, int x, int y)
224 : BC_FSlider(x, y, 0, 200, 200, 0, 100, plugin->config.slope)
226 this->plugin = plugin;
229 int DiffKeySlope::handle_event()
231 plugin->config.slope = get_value();
232 plugin->send_configure_change();
238 DiffKeyDoValue::DiffKeyDoValue(DiffKey *plugin, int x, int y)
239 : BC_CheckBox(x, y, plugin->config.do_value, _("Use Value"))
241 this->plugin = plugin;
244 int DiffKeyDoValue::handle_event()
246 plugin->config.do_value = get_value();
247 plugin->send_configure_change();
257 DiffKeyGUI::DiffKeyGUI(DiffKey *plugin, int x, int y)
258 : BC_Window(plugin->gui_string,
269 this->plugin = plugin;
272 DiffKeyGUI::~DiffKeyGUI()
277 void DiffKeyGUI::create_objects()
279 int x = 10, y = 10, x2;
281 add_subwindow(title = new BC_Title(x, y, _("Threshold:")));
282 x += title->get_w() + 10;
283 add_subwindow(threshold = new DiffKeyThreshold(plugin, x, y));
285 y += threshold->get_h() + 10;
286 add_subwindow(title = new BC_Title(x, y, _("Slope:")));
287 x += title->get_w() + 10;
288 add_subwindow(slope = new DiffKeySlope(plugin, x, y));
290 y += slope->get_h() + 10;
291 add_subwindow(do_value = new DiffKeyDoValue(plugin, x, y));
298 WINDOW_CLOSE_EVENT(DiffKeyGUI)
301 PLUGIN_THREAD_OBJECT(DiffKey, DiffKeyThread, DiffKeyGUI)
305 DiffKey::DiffKey(PluginServer *server)
306 : PluginVClient(server)
308 PLUGIN_CONSTRUCTOR_MACRO
314 PLUGIN_DESTRUCTOR_MACRO
318 SHOW_GUI_MACRO(DiffKey, DiffKeyThread)
319 RAISE_WINDOW_MACRO(DiffKey)
320 SET_STRING_MACRO(DiffKey)
321 #include "picon_png.h"
322 NEW_PICON_MACRO(DiffKey)
323 LOAD_CONFIGURATION_MACRO(DiffKey, DiffKeyConfig)
325 char* DiffKey::plugin_title() { return N_("Difference key"); }
326 int DiffKey::is_realtime() { return 1; }
327 int DiffKey::is_multichannel() { return 1; }
329 int DiffKey::load_defaults()
331 char directory[BCTEXTLEN];
332 // set the default directory
333 sprintf(directory, "%sdiffkey.rc", BCASTDIR);
336 defaults = new BC_Hash(directory);
339 config.threshold = defaults->get("THRESHOLD", config.threshold);
340 config.slope = defaults->get("SLOPE", config.slope);
341 config.do_value = defaults->get("DO_VALUE", config.do_value);
345 int DiffKey::save_defaults()
347 defaults->update("THRESHOLD", config.threshold);
348 defaults->update("SLOPE", config.slope);
349 defaults->update("DO_VALUE", config.do_value);
354 void DiffKey::save_data(KeyFrame *keyframe)
357 output.set_shared_string(keyframe->data, MESSAGESIZE);
358 output.tag.set_title("DIFFKEY");
359 output.tag.set_property("THRESHOLD", config.threshold);
360 output.tag.set_property("SLOPE", config.slope);
361 output.tag.set_property("DO_VALUE", config.do_value);
363 output.terminate_string();
366 void DiffKey::read_data(KeyFrame *keyframe)
370 input.set_shared_string(keyframe->data, strlen(keyframe->data));
372 while(!input.read_tag())
374 if(input.tag.title_is("DIFFKEY"))
376 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
377 config.slope = input.tag.get_property("SLOPE", config.slope);
378 config.do_value = input.tag.get_property("DO_VALUE", config.do_value);
383 void DiffKey::update_gui()
387 if(load_configuration())
389 thread->window->lock_window("DiffKey::update_gui");
390 thread->window->threshold->update(config.threshold);
391 thread->window->slope->update(config.slope);
392 thread->window->do_value->update(config.do_value);
393 thread->window->unlock_window();
398 int DiffKey::process_buffer(VFrame **frame,
399 int64_t start_position,
402 load_configuration();
404 // Don't process if only 1 layer.
405 if(get_total_buffers() < 2)
415 // Read frames from 2 layers
427 top_frame = frame[0];
428 bottom_frame = frame[1];
435 engine = new DiffKeyEngine(this);
438 engine->process_packages();
443 #define DIFFKEY_VARS(plugin) \
444 float threshold = plugin->config.threshold / 100; \
445 float pad = plugin->config.slope / 100; \
446 float threshold_pad = threshold + pad; \
449 int DiffKey::handle_opengl()
452 static char *diffkey_head =
453 "uniform sampler2D tex_bg;\n"
454 "uniform sampler2D tex_fg;\n"
455 "uniform float threshold;\n"
456 "uniform float pad;\n"
457 "uniform float threshold_pad;\n"
460 " vec4 foreground = texture2D(tex_fg, gl_TexCoord[0].st);\n"
461 " vec4 background = texture2D(tex_bg, gl_TexCoord[0].st);\n";
463 static char *colorcube =
464 " float difference = length(foreground.rgb - background.rgb);\n";
466 static char *yuv_value =
467 " float difference = abs(foreground.r - background.r);\n";
469 static char *rgb_value =
470 " float difference = abs(dot(foreground.rgb, vec3(0.29900, 0.58700, 0.11400)) - \n"
471 " dot(background.rgb, vec3(0.29900, 0.58700, 0.11400)));\n";
473 static char *diffkey_tail =
475 " if(difference < threshold)\n"
478 " if(difference < threshold_pad)\n"
479 " result.a = (difference - threshold) / pad;\n"
482 " result.rgb = foreground.rgb;\n"
483 " gl_FragColor = result;\n"
490 top_frame->enable_opengl();
491 top_frame->init_screen();
493 top_frame->to_texture();
494 bottom_frame->to_texture();
496 top_frame->enable_opengl();
497 top_frame->init_screen();
499 unsigned int shader_id = 0;
502 if(cmodel_is_yuv(top_frame->get_color_model()))
503 shader_id = VFrame::make_shader(0,
509 shader_id = VFrame::make_shader(0,
517 shader_id = VFrame::make_shader(0,
528 bottom_frame->bind_texture(1);
529 top_frame->bind_texture(0);
533 glUseProgram(shader_id);
534 glUniform1i(glGetUniformLocation(shader_id, "tex_fg"), 0);
535 glUniform1i(glGetUniformLocation(shader_id, "tex_bg"), 1);
536 glUniform1f(glGetUniformLocation(shader_id, "threshold"), threshold);
537 glUniform1f(glGetUniformLocation(shader_id, "pad"), pad);
538 glUniform1f(glGetUniformLocation(shader_id, "threshold_pad"), threshold_pad);
541 if(cmodel_components(get_output()->get_color_model()) == 3)
544 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
545 top_frame->clear_pbuffer();
548 top_frame->draw_texture();
550 top_frame->set_opengl_state(VFrame::SCREEN);
551 // Fastest way to discard output
552 bottom_frame->set_opengl_state(VFrame::TEXTURE);
563 DiffKeyEngine::DiffKeyEngine(DiffKey *plugin)
564 : LoadServer(plugin->get_project_smp() + 1, plugin->get_project_smp() + 1)
566 this->plugin = plugin;
569 void DiffKeyEngine::init_packages()
571 int increment = plugin->top_frame->get_h() / get_total_packages() + 1;
573 for(int i = 0; i < get_total_packages(); i++)
575 DiffKeyPackage *pkg = (DiffKeyPackage*)get_package(i);
577 pkg->row2 = MIN(y + increment, plugin->top_frame->get_h());
582 LoadClient* DiffKeyEngine::new_client()
584 return new DiffKeyClient(this);
587 LoadPackage* DiffKeyEngine::new_package()
589 return new DiffKeyPackage;
602 DiffKeyClient::DiffKeyClient(DiffKeyEngine *engine)
605 this->engine = engine;
608 DiffKeyClient::~DiffKeyClient()
612 void DiffKeyClient::process_package(LoadPackage *ptr)
614 DiffKeyPackage *pkg = (DiffKeyPackage*)ptr;
615 DiffKey *plugin = engine->plugin;
616 int w = plugin->top_frame->get_w();
618 #define RGB_TO_VALUE(r, g, b) \
619 ((r) * R_TO_Y + (g) * G_TO_Y + (b) * B_TO_Y)
621 #define SQR(x) ((x) * (x))
623 #define DIFFKEY_MACRO(type, components, max, chroma_offset) \
626 for(int i = pkg->row1; i < pkg->row2; i++) \
628 type *top_row = (type*)plugin->top_frame->get_rows()[i]; \
629 type *bottom_row = (type*)plugin->bottom_frame->get_rows()[i]; \
631 for(int j = 0; j < w; j++) \
635 /* Test for value in range */ \
636 if(plugin->config.do_value) \
639 float bottom_value; \
641 /* Convert pixel data into floating point value */ \
644 float top_r = (float)top_row[0] / max; \
645 float bottom_r = (float)bottom_row[0] / max; \
647 bottom_value = bottom_r; \
651 float top_r = (float)top_row[0] / max; \
652 float top_g = (float)top_row[1] / max; \
653 float top_b = (float)top_row[2] / max; \
654 top_g -= (float)chroma_offset / max; \
655 top_b -= (float)chroma_offset / max; \
657 float bottom_r = (float)bottom_row[0] / max; \
658 float bottom_g = (float)bottom_row[1] / max; \
659 float bottom_b = (float)bottom_row[2] / max; \
660 bottom_g -= (float)chroma_offset / max; \
661 bottom_b -= (float)chroma_offset / max; \
663 top_value = RGB_TO_VALUE(top_r, top_g, top_b); \
664 bottom_value = RGB_TO_VALUE(bottom_r, bottom_g, bottom_b); \
667 float min_v = bottom_value - threshold; \
668 float max_v = bottom_value + threshold; \
670 /* Full transparency if in range */ \
671 if(top_value >= min_v && top_value < max_v) \
676 /* Phased out if below or above range */ \
677 if(top_value < min_v) \
679 if(min_v - top_value < pad) \
680 a = (min_v - top_value) / pad; \
683 if(top_value - max_v < pad) \
684 a = (top_value - max_v) / pad; \
687 /* Use color cube */ \
689 float top_r = (float)top_row[0] / max; \
690 float top_g = (float)top_row[1] / max; \
691 float top_b = (float)top_row[2] / max; \
692 top_g -= (float)chroma_offset / max; \
693 top_b -= (float)chroma_offset / max; \
695 float bottom_r = (float)bottom_row[0] / max; \
696 float bottom_g = (float)bottom_row[1] / max; \
697 float bottom_b = (float)bottom_row[2] / max; \
698 bottom_g -= (float)chroma_offset / max; \
699 bottom_b -= (float)chroma_offset / max; \
702 float difference = sqrt(SQR(top_r - bottom_r) + \
703 SQR(top_g - bottom_g) + \
704 SQR(top_b - bottom_b)); \
706 if(difference < threshold) \
711 if(difference < threshold_pad) \
713 a = (difference - threshold) / pad; \
717 /* multiply alpha */ \
718 if(components == 4) \
720 top_row[3] = MIN((type)(a * max), top_row[3]); \
724 top_row[0] = (type)(a * top_row[0]); \
725 top_row[1] = (type)(a * (top_row[1] - chroma_offset) + chroma_offset); \
726 top_row[2] = (type)(a * (top_row[2] - chroma_offset) + chroma_offset); \
729 top_row += components; \
730 bottom_row += components; \
737 switch(plugin->top_frame->get_color_model())
740 DIFFKEY_MACRO(float, 3, 1.0, 0);
743 DIFFKEY_MACRO(float, 4, 1.0, 0);
746 DIFFKEY_MACRO(unsigned char, 3, 0xff, 0);
749 DIFFKEY_MACRO(unsigned char, 4, 0xff, 0);
752 DIFFKEY_MACRO(unsigned char, 3, 0xff, 0x80);
755 DIFFKEY_MACRO(unsigned char, 4, 0xff, 0x80);
766 DiffKeyPackage::DiffKeyPackage()