00001 #ifndef DIFFKEY_H
00002 #define DIFFKEY_H
00003
00004 #include "bcdisplayinfo.h"
00005 #include "clip.h"
00006 #include "bchash.h"
00007 #include "filexml.h"
00008 #include "guicast.h"
00009 #include "language.h"
00010 #include "loadbalance.h"
00011 #include "plugincolors.h"
00012 #include "pluginvclient.h"
00013
00014
00015 #include <string.h>
00016
00017
00018
00019 class DiffKeyGUI;
00020 class DiffKey;
00021
00022
00023
00024 class DiffKeyConfig
00025 {
00026 public:
00027 DiffKeyConfig();
00028 void copy_from(DiffKeyConfig &src);
00029 int equivalent(DiffKeyConfig &src);
00030 void interpolate(DiffKeyConfig &prev,
00031 DiffKeyConfig &next,
00032 int64_t prev_frame,
00033 int64_t next_frame,
00034 int64_t current_frame);
00035
00036 float threshold;
00037 float slope;
00038 int do_value;
00039 };
00040
00041
00042 class DiffKeyThreshold : public BC_FSlider
00043 {
00044 public:
00045 DiffKeyThreshold(DiffKey *plugin, int x, int y);
00046 int handle_event();
00047 DiffKey *plugin;
00048 };
00049
00050 class DiffKeySlope : public BC_FSlider
00051 {
00052 public:
00053 DiffKeySlope(DiffKey *plugin, int x, int y);
00054 int handle_event();
00055 DiffKey *plugin;
00056 };
00057
00058 class DiffKeyDoValue : public BC_CheckBox
00059 {
00060 public:
00061 DiffKeyDoValue(DiffKey *plugin, int x, int y);
00062 int handle_event();
00063 DiffKey *plugin;
00064 };
00065
00066
00067
00068 class DiffKeyGUI : public BC_Window
00069 {
00070 public:
00071 DiffKeyGUI(DiffKey *plugin, int x, int y);
00072 ~DiffKeyGUI();
00073
00074
00075 void create_objects();
00076 int close_event();
00077
00078
00079 DiffKeyThreshold *threshold;
00080 DiffKeySlope *slope;
00081 DiffKeyDoValue *do_value;
00082 DiffKey *plugin;
00083 };
00084
00085
00086 PLUGIN_THREAD_HEADER(DiffKey, DiffKeyThread, DiffKeyGUI)
00087
00088
00089
00090 class DiffKeyEngine : public LoadServer
00091 {
00092 public:
00093 DiffKeyEngine(DiffKey *plugin);
00094 void init_packages();
00095 LoadClient* new_client();
00096 LoadPackage* new_package();
00097 DiffKey *plugin;
00098 };
00099
00100
00101 class DiffKeyClient : public LoadClient
00102 {
00103 public:
00104 DiffKeyClient(DiffKeyEngine *engine);
00105 ~DiffKeyClient();
00106
00107 void process_package(LoadPackage *pkg);
00108 DiffKeyEngine *engine;
00109 };
00110
00111 class DiffKeyPackage : public LoadPackage
00112 {
00113 public:
00114 DiffKeyPackage();
00115 int row1;
00116 int row2;
00117 };
00118
00119
00120
00121 class DiffKey : public PluginVClient
00122 {
00123 public:
00124 DiffKey(PluginServer *server);
00125 ~DiffKey();
00126
00127 int process_buffer(VFrame **frame,
00128 int64_t start_position,
00129 double frame_rate);
00130 int is_realtime();
00131 int is_multichannel();
00132 int load_defaults();
00133 int save_defaults();
00134 void save_data(KeyFrame *keyframe);
00135 void read_data(KeyFrame *keyframe);
00136 void update_gui();
00137 int handle_opengl();
00138
00139
00140
00141 PLUGIN_CLASS_MEMBERS(DiffKeyConfig, DiffKeyThread)
00142
00143 DiffKeyEngine *engine;
00144 VFrame *top_frame;
00145 VFrame *bottom_frame;
00146 };
00147
00148
00149
00150
00151
00152
00153
00154
00155 REGISTER_PLUGIN(DiffKey)
00156
00157
00158 DiffKeyConfig::DiffKeyConfig()
00159 {
00160 threshold = 0.1;
00161 slope = 0;
00162 do_value = 0;
00163 }
00164
00165 void DiffKeyConfig::copy_from(DiffKeyConfig &src)
00166 {
00167 this->threshold = src.threshold;
00168 this->slope = src.slope;
00169 this->do_value = src.do_value;
00170 }
00171
00172
00173 int DiffKeyConfig::equivalent(DiffKeyConfig &src)
00174 {
00175 return EQUIV(threshold, src.threshold) &&
00176 EQUIV(slope, src.slope) &&
00177 do_value == src.do_value;
00178 }
00179
00180 void DiffKeyConfig::interpolate(DiffKeyConfig &prev,
00181 DiffKeyConfig &next,
00182 int64_t prev_frame,
00183 int64_t next_frame,
00184 int64_t current_frame)
00185 {
00186 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
00187 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
00188
00189 this->threshold = prev.threshold * prev_scale + next.threshold * next_scale;
00190 this->slope = prev.slope * prev_scale + next.slope * next_scale;
00191 this->do_value = prev.do_value;
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203 DiffKeyThreshold::DiffKeyThreshold(DiffKey *plugin, int x, int y)
00204 : BC_FSlider(x, y, 0, 200, 200, 0, 100, plugin->config.threshold)
00205 {
00206 this->plugin = plugin;
00207 }
00208
00209 int DiffKeyThreshold::handle_event()
00210 {
00211 plugin->config.threshold = get_value();
00212 plugin->send_configure_change();
00213 return 1;
00214 }
00215
00216
00217
00218
00219
00220
00221
00222
00223 DiffKeySlope::DiffKeySlope(DiffKey *plugin, int x, int y)
00224 : BC_FSlider(x, y, 0, 200, 200, 0, 100, plugin->config.slope)
00225 {
00226 this->plugin = plugin;
00227 }
00228
00229 int DiffKeySlope::handle_event()
00230 {
00231 plugin->config.slope = get_value();
00232 plugin->send_configure_change();
00233 return 1;
00234 }
00235
00236
00237
00238 DiffKeyDoValue::DiffKeyDoValue(DiffKey *plugin, int x, int y)
00239 : BC_CheckBox(x, y, plugin->config.do_value, _("Use Value"))
00240 {
00241 this->plugin = plugin;
00242 }
00243
00244 int DiffKeyDoValue::handle_event()
00245 {
00246 plugin->config.do_value = get_value();
00247 plugin->send_configure_change();
00248 return 1;
00249 }
00250
00251
00252
00253
00254
00255
00256
00257 DiffKeyGUI::DiffKeyGUI(DiffKey *plugin, int x, int y)
00258 : BC_Window(plugin->gui_string,
00259 x,
00260 y,
00261 320,
00262 100,
00263 320,
00264 100,
00265 0,
00266 0,
00267 1)
00268 {
00269 this->plugin = plugin;
00270 }
00271
00272 DiffKeyGUI::~DiffKeyGUI()
00273 {
00274 }
00275
00276
00277 void DiffKeyGUI::create_objects()
00278 {
00279 int x = 10, y = 10, x2;
00280 BC_Title *title;
00281 add_subwindow(title = new BC_Title(x, y, _("Threshold:")));
00282 x += title->get_w() + 10;
00283 add_subwindow(threshold = new DiffKeyThreshold(plugin, x, y));
00284 x = 10;
00285 y += threshold->get_h() + 10;
00286 add_subwindow(title = new BC_Title(x, y, _("Slope:")));
00287 x += title->get_w() + 10;
00288 add_subwindow(slope = new DiffKeySlope(plugin, x, y));
00289 x = 10;
00290 y += slope->get_h() + 10;
00291 add_subwindow(do_value = new DiffKeyDoValue(plugin, x, y));
00292
00293
00294
00295 show_window();
00296 }
00297
00298 WINDOW_CLOSE_EVENT(DiffKeyGUI)
00299
00300
00301 PLUGIN_THREAD_OBJECT(DiffKey, DiffKeyThread, DiffKeyGUI)
00302
00303
00304
00305 DiffKey::DiffKey(PluginServer *server)
00306 : PluginVClient(server)
00307 {
00308 PLUGIN_CONSTRUCTOR_MACRO
00309 engine = 0;
00310 }
00311
00312 DiffKey::~DiffKey()
00313 {
00314 PLUGIN_DESTRUCTOR_MACRO
00315 delete engine;
00316 }
00317
00318 SHOW_GUI_MACRO(DiffKey, DiffKeyThread)
00319 RAISE_WINDOW_MACRO(DiffKey)
00320 SET_STRING_MACRO(DiffKey)
00321 #include "picon_png.h"
00322 NEW_PICON_MACRO(DiffKey)
00323 LOAD_CONFIGURATION_MACRO(DiffKey, DiffKeyConfig)
00324
00325 char* DiffKey::plugin_title() { return N_("Difference key"); }
00326 int DiffKey::is_realtime() { return 1; }
00327 int DiffKey::is_multichannel() { return 1; }
00328
00329 int DiffKey::load_defaults()
00330 {
00331 char directory[BCTEXTLEN];
00332
00333 sprintf(directory, "%sdiffkey.rc", BCASTDIR);
00334
00335
00336 defaults = new BC_Hash(directory);
00337 defaults->load();
00338
00339 config.threshold = defaults->get("THRESHOLD", config.threshold);
00340 config.slope = defaults->get("SLOPE", config.slope);
00341 config.do_value = defaults->get("DO_VALUE", config.do_value);
00342 return 0;
00343 }
00344
00345 int DiffKey::save_defaults()
00346 {
00347 defaults->update("THRESHOLD", config.threshold);
00348 defaults->update("SLOPE", config.slope);
00349 defaults->update("DO_VALUE", config.do_value);
00350 defaults->save();
00351 return 0;
00352 }
00353
00354 void DiffKey::save_data(KeyFrame *keyframe)
00355 {
00356 FileXML output;
00357 output.set_shared_string(keyframe->data, MESSAGESIZE);
00358 output.tag.set_title("DIFFKEY");
00359 output.tag.set_property("THRESHOLD", config.threshold);
00360 output.tag.set_property("SLOPE", config.slope);
00361 output.tag.set_property("DO_VALUE", config.do_value);
00362 output.append_tag();
00363 output.tag.set_title("/DIFFKEY");
00364 output.append_tag();
00365 output.terminate_string();
00366 }
00367
00368 void DiffKey::read_data(KeyFrame *keyframe)
00369 {
00370 FileXML input;
00371
00372 input.set_shared_string(keyframe->data, strlen(keyframe->data));
00373
00374 while(!input.read_tag())
00375 {
00376 if(input.tag.title_is("DIFFKEY"))
00377 {
00378 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
00379 config.slope = input.tag.get_property("SLOPE", config.slope);
00380 config.do_value = input.tag.get_property("DO_VALUE", config.do_value);
00381 }
00382 }
00383 }
00384
00385 void DiffKey::update_gui()
00386 {
00387 if(thread)
00388 {
00389 if(load_configuration())
00390 {
00391 thread->window->lock_window("DiffKey::update_gui");
00392 thread->window->threshold->update(config.threshold);
00393 thread->window->slope->update(config.slope);
00394 thread->window->do_value->update(config.do_value);
00395 thread->window->unlock_window();
00396 }
00397 }
00398 }
00399
00400 int DiffKey::process_buffer(VFrame **frame,
00401 int64_t start_position,
00402 double frame_rate)
00403 {
00404 load_configuration();
00405
00406
00407 if(get_total_buffers() < 2)
00408 {
00409 read_frame(frame[0],
00410 0,
00411 start_position,
00412 frame_rate,
00413 get_use_opengl());
00414 return 0;
00415 }
00416
00417
00418 read_frame(frame[0],
00419 0,
00420 start_position,
00421 frame_rate,
00422 get_use_opengl());
00423 read_frame(frame[1],
00424 1,
00425 start_position,
00426 frame_rate,
00427 get_use_opengl());
00428
00429 top_frame = frame[0];
00430 bottom_frame = frame[1];
00431
00432 if(get_use_opengl())
00433 return run_opengl();
00434
00435 if(!engine)
00436 {
00437 engine = new DiffKeyEngine(this);
00438 }
00439
00440 engine->process_packages();
00441
00442 return 0;
00443 }
00444
00445 #define DIFFKEY_VARS(plugin) \
00446 float threshold = plugin->config.threshold / 100; \
00447 float pad = plugin->config.slope / 100; \
00448 float threshold_pad = threshold + pad; \
00449
00450
00451 int DiffKey::handle_opengl()
00452 {
00453 #ifdef HAVE_GL
00454 static char *diffkey_head =
00455 "uniform sampler2D tex_bg;\n"
00456 "uniform sampler2D tex_fg;\n"
00457 "uniform float threshold;\n"
00458 "uniform float pad;\n"
00459 "uniform float threshold_pad;\n"
00460 "void main()\n"
00461 "{\n"
00462 " vec4 foreground = texture2D(tex_fg, gl_TexCoord[0].st);\n"
00463 " vec4 background = texture2D(tex_bg, gl_TexCoord[0].st);\n";
00464
00465 static char *colorcube =
00466 " float difference = length(foreground.rgb - background.rgb);\n";
00467
00468 static char *yuv_value =
00469 " float difference = abs(foreground.r - background.r);\n";
00470
00471 static char *rgb_value =
00472 " float difference = abs(dot(foreground.rgb, vec3(0.29900, 0.58700, 0.11400)) - \n"
00473 " dot(background.rgb, vec3(0.29900, 0.58700, 0.11400)));\n";
00474
00475 static char *diffkey_tail =
00476 " vec4 result;\n"
00477 " if(difference < threshold)\n"
00478 " result.a = 0.0;\n"
00479 " else\n"
00480 " if(difference < threshold_pad)\n"
00481 " result.a = (difference - threshold) / pad;\n"
00482 " else\n"
00483 " result.a = 1.0;\n"
00484 " result.rgb = foreground.rgb;\n"
00485 " gl_FragColor = result;\n"
00486 "}\n";
00487
00488
00489
00490
00491
00492 top_frame->enable_opengl();
00493 top_frame->init_screen();
00494
00495 top_frame->to_texture();
00496 bottom_frame->to_texture();
00497
00498 top_frame->enable_opengl();
00499 top_frame->init_screen();
00500
00501 unsigned int shader_id = 0;
00502 if(config.do_value)
00503 {
00504 if(cmodel_is_yuv(top_frame->get_color_model()))
00505 shader_id = VFrame::make_shader(0,
00506 diffkey_head,
00507 yuv_value,
00508 diffkey_tail,
00509 0);
00510 else
00511 shader_id = VFrame::make_shader(0,
00512 diffkey_head,
00513 rgb_value,
00514 diffkey_tail,
00515 0);
00516 }
00517 else
00518 {
00519 shader_id = VFrame::make_shader(0,
00520 diffkey_head,
00521 colorcube,
00522 diffkey_tail,
00523 0);
00524 }
00525
00526
00527
00528 DIFFKEY_VARS(this)
00529
00530 bottom_frame->bind_texture(1);
00531 top_frame->bind_texture(0);
00532
00533 if(shader_id > 0)
00534 {
00535 glUseProgram(shader_id);
00536 glUniform1i(glGetUniformLocation(shader_id, "tex_fg"), 0);
00537 glUniform1i(glGetUniformLocation(shader_id, "tex_bg"), 1);
00538 glUniform1f(glGetUniformLocation(shader_id, "threshold"), threshold);
00539 glUniform1f(glGetUniformLocation(shader_id, "pad"), pad);
00540 glUniform1f(glGetUniformLocation(shader_id, "threshold_pad"), threshold_pad);
00541 }
00542
00543 if(cmodel_components(get_output()->get_color_model()) == 3)
00544 {
00545 glEnable(GL_BLEND);
00546 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00547 top_frame->clear_pbuffer();
00548 }
00549
00550 top_frame->draw_texture();
00551 glUseProgram(0);
00552 top_frame->set_opengl_state(VFrame::SCREEN);
00553
00554 bottom_frame->set_opengl_state(VFrame::TEXTURE);
00555 glDisable(GL_BLEND);
00556
00557
00558 #endif
00559 return 0;
00560 }
00561
00562
00563
00564
00565 DiffKeyEngine::DiffKeyEngine(DiffKey *plugin)
00566 : LoadServer(plugin->get_project_smp() + 1, plugin->get_project_smp() + 1)
00567 {
00568 this->plugin = plugin;
00569 }
00570
00571 void DiffKeyEngine::init_packages()
00572 {
00573 int increment = plugin->top_frame->get_h() / get_total_packages() + 1;
00574 int y = 0;
00575 for(int i = 0; i < get_total_packages(); i++)
00576 {
00577 DiffKeyPackage *pkg = (DiffKeyPackage*)get_package(i);
00578 pkg->row1 = y;
00579 pkg->row2 = MIN(y + increment, plugin->top_frame->get_h());
00580 y += increment;
00581 }
00582 }
00583
00584 LoadClient* DiffKeyEngine::new_client()
00585 {
00586 return new DiffKeyClient(this);
00587 }
00588
00589 LoadPackage* DiffKeyEngine::new_package()
00590 {
00591 return new DiffKeyPackage;
00592 }
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604 DiffKeyClient::DiffKeyClient(DiffKeyEngine *engine)
00605 : LoadClient(engine)
00606 {
00607 this->engine = engine;
00608 }
00609
00610 DiffKeyClient::~DiffKeyClient()
00611 {
00612 }
00613
00614 void DiffKeyClient::process_package(LoadPackage *ptr)
00615 {
00616 DiffKeyPackage *pkg = (DiffKeyPackage*)ptr;
00617 DiffKey *plugin = engine->plugin;
00618 int w = plugin->top_frame->get_w();
00619
00620 #define RGB_TO_VALUE(r, g, b) \
00621 ((r) * R_TO_Y + (g) * G_TO_Y + (b) * B_TO_Y)
00622
00623 #define SQR(x) ((x) * (x))
00624
00625 #define DIFFKEY_MACRO(type, components, max, chroma_offset) \
00626 { \
00627 \
00628 for(int i = pkg->row1; i < pkg->row2; i++) \
00629 { \
00630 type *top_row = (type*)plugin->top_frame->get_rows()[i]; \
00631 type *bottom_row = (type*)plugin->bottom_frame->get_rows()[i]; \
00632 \
00633 for(int j = 0; j < w; j++) \
00634 { \
00635 float a = 1.0; \
00636 \
00637 \
00638 if(plugin->config.do_value) \
00639 { \
00640 float top_value; \
00641 float bottom_value; \
00642 \
00643 \
00644 if(chroma_offset) \
00645 { \
00646 float top_r = (float)top_row[0] / max; \
00647 float bottom_r = (float)bottom_row[0] / max; \
00648 top_value = top_r; \
00649 bottom_value = bottom_r; \
00650 } \
00651 else \
00652 { \
00653 float top_r = (float)top_row[0] / max; \
00654 float top_g = (float)top_row[1] / max; \
00655 float top_b = (float)top_row[2] / max; \
00656 top_g -= (float)chroma_offset / max; \
00657 top_b -= (float)chroma_offset / max; \
00658 \
00659 float bottom_r = (float)bottom_row[0] / max; \
00660 float bottom_g = (float)bottom_row[1] / max; \
00661 float bottom_b = (float)bottom_row[2] / max; \
00662 bottom_g -= (float)chroma_offset / max; \
00663 bottom_b -= (float)chroma_offset / max; \
00664 \
00665 top_value = RGB_TO_VALUE(top_r, top_g, top_b); \
00666 bottom_value = RGB_TO_VALUE(bottom_r, bottom_g, bottom_b); \
00667 } \
00668 \
00669 float min_v = bottom_value - threshold; \
00670 float max_v = bottom_value + threshold; \
00671 \
00672 \
00673 if(top_value >= min_v && top_value < max_v) \
00674 { \
00675 a = 0; \
00676 } \
00677 else \
00678 \
00679 if(top_value < min_v) \
00680 { \
00681 if(min_v - top_value < pad) \
00682 a = (min_v - top_value) / pad; \
00683 } \
00684 else \
00685 if(top_value - max_v < pad) \
00686 a = (top_value - max_v) / pad; \
00687 } \
00688 else \
00689 \
00690 { \
00691 float top_r = (float)top_row[0] / max; \
00692 float top_g = (float)top_row[1] / max; \
00693 float top_b = (float)top_row[2] / max; \
00694 top_g -= (float)chroma_offset / max; \
00695 top_b -= (float)chroma_offset / max; \
00696 \
00697 float bottom_r = (float)bottom_row[0] / max; \
00698 float bottom_g = (float)bottom_row[1] / max; \
00699 float bottom_b = (float)bottom_row[2] / max; \
00700 bottom_g -= (float)chroma_offset / max; \
00701 bottom_b -= (float)chroma_offset / max; \
00702 \
00703 \
00704 float difference = sqrt(SQR(top_r - bottom_r) + \
00705 SQR(top_g - bottom_g) + \
00706 SQR(top_b - bottom_b)); \
00707 \
00708 if(difference < threshold) \
00709 { \
00710 a = 0; \
00711 } \
00712 else \
00713 if(difference < threshold_pad) \
00714 { \
00715 a = (difference - threshold) / pad; \
00716 } \
00717 } \
00718 \
00719 \
00720 if(components == 4) \
00721 { \
00722 top_row[3] = MIN((type)(a * max), top_row[3]); \
00723 } \
00724 else \
00725 { \
00726 top_row[0] = (type)(a * top_row[0]); \
00727 top_row[1] = (type)(a * (top_row[1] - chroma_offset) + chroma_offset); \
00728 top_row[2] = (type)(a * (top_row[2] - chroma_offset) + chroma_offset); \
00729 } \
00730 \
00731 top_row += components; \
00732 bottom_row += components; \
00733 } \
00734 } \
00735 }
00736
00737 DIFFKEY_VARS(plugin)
00738
00739 switch(plugin->top_frame->get_color_model())
00740 {
00741 case BC_RGB_FLOAT:
00742 DIFFKEY_MACRO(float, 3, 1.0, 0);
00743 break;
00744 case BC_RGBA_FLOAT:
00745 DIFFKEY_MACRO(float, 4, 1.0, 0);
00746 break;
00747 case BC_RGB888:
00748 DIFFKEY_MACRO(unsigned char, 3, 0xff, 0);
00749 break;
00750 case BC_RGBA8888:
00751 DIFFKEY_MACRO(unsigned char, 4, 0xff, 0);
00752 break;
00753 case BC_YUV888:
00754 DIFFKEY_MACRO(unsigned char, 3, 0xff, 0x80);
00755 break;
00756 case BC_YUVA8888:
00757 DIFFKEY_MACRO(unsigned char, 4, 0xff, 0x80);
00758 break;
00759 }
00760
00761
00762
00763 }
00764
00765
00766
00767
00768 DiffKeyPackage::DiffKeyPackage()
00769 : LoadPackage()
00770 {
00771 }
00772
00773
00774
00775
00776
00777
00778 #endif