00001 #include "bcdisplayinfo.h"
00002 #include "clip.h"
00003 #include "bchash.h"
00004 #include "filexml.h"
00005 #include "guicast.h"
00006 #include "language.h"
00007 #include "picon_png.h"
00008 #include "plugincolors.h"
00009 #include "pluginvclient.h"
00010 #include "vframe.h"
00011
00012 #include <stdint.h>
00013 #include <string.h>
00014
00015
00016
00017 class InvertVideoEffect;
00018
00019
00020 class InvertVideoConfig
00021 {
00022 public:
00023 InvertVideoConfig();
00024
00025 void copy_from(InvertVideoConfig &src);
00026 int equivalent(InvertVideoConfig &src);
00027 void interpolate(InvertVideoConfig &prev,
00028 InvertVideoConfig &next,
00029 long prev_frame,
00030 long next_frame,
00031 long current_frame);
00032
00033 int r, g, b, a;
00034 };
00035
00036 class InvertVideoEnable : public BC_CheckBox
00037 {
00038 public:
00039 InvertVideoEnable(InvertVideoEffect *plugin, int *output, int x, int y, char *text);
00040 int handle_event();
00041 InvertVideoEffect *plugin;
00042 int *output;
00043 };
00044
00045 class InvertVideoWindow : public BC_Window
00046 {
00047 public:
00048 InvertVideoWindow(InvertVideoEffect *plugin, int x, int y);
00049 void create_objects();
00050 int close_event();
00051 InvertVideoEnable *r, *g, *b, *a;
00052 InvertVideoEffect *plugin;
00053 };
00054
00055 PLUGIN_THREAD_HEADER(InvertVideoEffect, InvertVideoThread, InvertVideoWindow)
00056
00057 class InvertVideoEffect : public PluginVClient
00058 {
00059 public:
00060 InvertVideoEffect(PluginServer *server);
00061 ~InvertVideoEffect();
00062 int process_buffer(VFrame *frame,
00063 int64_t start_position,
00064 double frame_rate);
00065 int is_realtime();
00066 char* plugin_title();
00067 VFrame* new_picon();
00068 int load_defaults();
00069 int save_defaults();
00070 void save_data(KeyFrame *keyframe);
00071 void read_data(KeyFrame *keyframe);
00072 void update_gui();
00073 int show_gui();
00074 void raise_window();
00075 int set_string();
00076 int load_configuration();
00077 int handle_opengl();
00078
00079 InvertVideoConfig config;
00080 InvertVideoThread *thread;
00081 BC_Hash *defaults;
00082 };
00083
00084
00085
00086
00087
00088 REGISTER_PLUGIN(InvertVideoEffect)
00089
00090
00091
00092
00093
00094
00095
00096 InvertVideoConfig::InvertVideoConfig()
00097 {
00098 r = 1;
00099 g = 1;
00100 b = 1;
00101 a = 1;
00102 }
00103
00104 void InvertVideoConfig::copy_from(InvertVideoConfig &src)
00105 {
00106 r = src.r;
00107 g = src.g;
00108 b = src.b;
00109 a = src.a;
00110 }
00111
00112 int InvertVideoConfig::equivalent(InvertVideoConfig &src)
00113 {
00114 return r == src.r &&
00115 g == src.g &&
00116 b == src.b &&
00117 a == src.a;
00118 }
00119
00120 void InvertVideoConfig::interpolate(InvertVideoConfig &prev,
00121 InvertVideoConfig &next,
00122 long prev_frame,
00123 long next_frame,
00124 long current_frame)
00125 {
00126 r = prev.r;
00127 g = prev.g;
00128 b = prev.b;
00129 a = prev.a;
00130 }
00131
00132
00133
00134
00135 InvertVideoEnable::InvertVideoEnable(InvertVideoEffect *plugin, int *output, int x, int y, char *text)
00136 : BC_CheckBox(x, y, *output, text)
00137 {
00138 this->plugin = plugin;
00139 this->output = output;
00140 }
00141 int InvertVideoEnable::handle_event()
00142 {
00143 *output = get_value();
00144 plugin->send_configure_change();
00145 return 1;
00146 }
00147
00148
00149
00150
00151
00152 InvertVideoWindow::InvertVideoWindow(InvertVideoEffect *plugin, int x, int y)
00153 : BC_Window(plugin->gui_string,
00154 x,
00155 y,
00156 260,
00157 130,
00158 260,
00159 130,
00160 0,
00161 0,
00162 1)
00163 {
00164 this->plugin = plugin;
00165 }
00166
00167 void InvertVideoWindow::create_objects()
00168 {
00169 int x = 10, y = 10;
00170 add_subwindow(r = new InvertVideoEnable(plugin, &plugin->config.r, x, y, _("Invert R")));
00171 y += 30;
00172 add_subwindow(g = new InvertVideoEnable(plugin, &plugin->config.g, x, y, _("Invert G")));
00173 y += 30;
00174 add_subwindow(b = new InvertVideoEnable(plugin, &plugin->config.b, x, y, _("Invert B")));
00175 y += 30;
00176 add_subwindow(a = new InvertVideoEnable(plugin, &plugin->config.a, x, y, _("Invert A")));
00177
00178 show_window();
00179 flush();
00180 }
00181
00182 WINDOW_CLOSE_EVENT(InvertVideoWindow)
00183
00184
00185
00186
00187
00188 PLUGIN_THREAD_OBJECT(InvertVideoEffect, InvertVideoThread, InvertVideoWindow)
00189
00190
00191
00192
00193
00194
00195 InvertVideoEffect::InvertVideoEffect(PluginServer *server)
00196 : PluginVClient(server)
00197 {
00198 PLUGIN_CONSTRUCTOR_MACRO
00199 }
00200 InvertVideoEffect::~InvertVideoEffect()
00201 {
00202 PLUGIN_DESTRUCTOR_MACRO
00203 }
00204
00205 char* InvertVideoEffect::plugin_title() { return N_("Invert Video"); }
00206 int InvertVideoEffect::is_realtime() { return 1; }
00207
00208 NEW_PICON_MACRO(InvertVideoEffect)
00209 SHOW_GUI_MACRO(InvertVideoEffect, InvertVideoThread)
00210 RAISE_WINDOW_MACRO(InvertVideoEffect)
00211 SET_STRING_MACRO(InvertVideoEffect)
00212 LOAD_CONFIGURATION_MACRO(InvertVideoEffect, InvertVideoConfig)
00213
00214 void InvertVideoEffect::update_gui()
00215 {
00216 if(thread)
00217 {
00218 thread->window->lock_window();
00219 load_configuration();
00220 thread->window->r->update(config.r);
00221 thread->window->g->update(config.g);
00222 thread->window->b->update(config.b);
00223 thread->window->a->update(config.a);
00224 thread->window->unlock_window();
00225 }
00226 }
00227
00228 int InvertVideoEffect::load_defaults()
00229 {
00230 char directory[BCTEXTLEN];
00231 sprintf(directory, "%sinvertvideo.rc", BCASTDIR);
00232 defaults = new BC_Hash(directory);
00233 defaults->load();
00234 config.r = defaults->get("R", config.r);
00235 config.g = defaults->get("G", config.g);
00236 config.b = defaults->get("B", config.b);
00237 config.a = defaults->get("A", config.a);
00238 return 0;
00239 }
00240
00241 int InvertVideoEffect::save_defaults()
00242 {
00243 defaults->update("R", config.r);
00244 defaults->update("G", config.g);
00245 defaults->update("B", config.b);
00246 defaults->update("A", config.a);
00247 defaults->save();
00248 return 0;
00249 }
00250
00251 void InvertVideoEffect::save_data(KeyFrame *keyframe)
00252 {
00253 FileXML output;
00254 output.set_shared_string(keyframe->data, MESSAGESIZE);
00255 output.tag.set_title("INVERTVIDEO");
00256 output.tag.set_property("R", config.r);
00257 output.tag.set_property("G", config.g);
00258 output.tag.set_property("B", config.b);
00259 output.tag.set_property("A", config.a);
00260 output.append_tag();
00261 output.tag.set_title("/INVERTVIDEO");
00262 output.append_tag();
00263 output.terminate_string();
00264 }
00265
00266 void InvertVideoEffect::read_data(KeyFrame *keyframe)
00267 {
00268 FileXML input;
00269 input.set_shared_string(keyframe->data, strlen(keyframe->data));
00270 while(!input.read_tag())
00271 {
00272 if(input.tag.title_is("INVERTVIDEO"))
00273 {
00274 config.r = input.tag.get_property("R", config.r);
00275 config.g = input.tag.get_property("G", config.g);
00276 config.b = input.tag.get_property("B", config.b);
00277 config.a = input.tag.get_property("A", config.a);
00278 }
00279 }
00280 }
00281
00282
00283 #define INVERT_MACRO(type, components, max) \
00284 { \
00285 for(int i = 0; i < frame->get_h(); i++) \
00286 { \
00287 type *in_row = (type*)frame->get_rows()[i]; \
00288 type *out_row = (type*)frame->get_rows()[i]; \
00289 \
00290 for(int j = 0; j < w; j++) \
00291 { \
00292 if(config.r) out_row[0] = max - in_row[0]; \
00293 if(config.g) out_row[1] = max - in_row[1]; \
00294 if(config.b) out_row[2] = max - in_row[2]; \
00295 if(components == 4) \
00296 if(config.a) out_row[3] = max - in_row[3]; \
00297 \
00298 in_row += components; \
00299 out_row += components; \
00300 } \
00301 } \
00302 }
00303
00304 int InvertVideoEffect::process_buffer(VFrame *frame,
00305 int64_t start_position,
00306 double frame_rate)
00307 {
00308 load_configuration();
00309
00310 read_frame(frame,
00311 0,
00312 start_position,
00313 frame_rate,
00314 get_use_opengl());
00315
00316
00317 if(config.r || config.g || config.b || config.a)
00318 {
00319 if(get_use_opengl())
00320 {
00321 run_opengl();
00322 return 0;
00323 }
00324 int w = frame->get_w();
00325
00326 switch(frame->get_color_model())
00327 {
00328 case BC_RGB_FLOAT:
00329 INVERT_MACRO(float, 3, 1.0)
00330 break;
00331 case BC_RGB888:
00332 case BC_YUV888:
00333 INVERT_MACRO(unsigned char, 3, 0xff)
00334 break;
00335 case BC_RGBA_FLOAT:
00336 INVERT_MACRO(float, 4, 1.0)
00337 break;
00338 case BC_RGBA8888:
00339 case BC_YUVA8888:
00340 INVERT_MACRO(unsigned char, 4, 0xff)
00341 break;
00342 case BC_RGB161616:
00343 case BC_YUV161616:
00344 INVERT_MACRO(uint16_t, 3, 0xffff)
00345 break;
00346 case BC_RGBA16161616:
00347 case BC_YUVA16161616:
00348 INVERT_MACRO(uint16_t, 4, 0xffff)
00349 break;
00350 }
00351 }
00352
00353 return 0;
00354 }
00355
00356 int InvertVideoEffect::handle_opengl()
00357 {
00358 #ifdef HAVE_GL
00359 static char *invert_frag =
00360 "uniform sampler2D tex;\n"
00361 "uniform bool do_r;\n"
00362 "uniform bool do_g;\n"
00363 "uniform bool do_b;\n"
00364 "uniform bool do_a;\n"
00365 "void main()\n"
00366 "{\n"
00367 " gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
00368 " if(do_r) gl_FragColor.r = 1.0 - gl_FragColor.r;\n"
00369 " if(do_g) gl_FragColor.g = 1.0 - gl_FragColor.g;\n"
00370 " if(do_b) gl_FragColor.b = 1.0 - gl_FragColor.b;\n"
00371 " if(do_a) gl_FragColor.a = 1.0 - gl_FragColor.a;\n"
00372 "}\n";
00373
00374 get_output()->to_texture();
00375 get_output()->enable_opengl();
00376
00377 unsigned int frag_shader = 0;
00378 frag_shader = VFrame::make_shader(0,
00379 invert_frag,
00380 0);
00381 glUseProgram(frag_shader);
00382 glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
00383 glUniform1i(glGetUniformLocation(frag_shader, "do_r"), config.r);
00384 glUniform1i(glGetUniformLocation(frag_shader, "do_g"), config.g);
00385 glUniform1i(glGetUniformLocation(frag_shader, "do_b"), config.b);
00386 glUniform1i(glGetUniformLocation(frag_shader, "do_a"), config.a);
00387
00388
00389 VFrame::init_screen(get_output()->get_w(), get_output()->get_h());
00390 get_output()->bind_texture(0);
00391 get_output()->draw_texture();
00392 glUseProgram(0);
00393 get_output()->set_opengl_state(VFrame::SCREEN);
00394 #endif
00395 }
00396
00397