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