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 class YUVEffect;
00017
00018
00019 class YUVConfig
00020 {
00021 public:
00022 YUVConfig();
00023
00024 void copy_from(YUVConfig &src);
00025 int equivalent(YUVConfig &src);
00026 void interpolate(YUVConfig &prev,
00027 YUVConfig &next,
00028 long prev_frame,
00029 long next_frame,
00030 long current_frame);
00031
00032 float y, u, v;
00033 };
00034
00035 class YUVLevel : public BC_FSlider
00036 {
00037 public:
00038 YUVLevel(YUVEffect *plugin, float *output, int x, int y);
00039 int handle_event();
00040 YUVEffect *plugin;
00041 float *output;
00042 };
00043
00044 class YUVWindow : public BC_Window
00045 {
00046 public:
00047 YUVWindow(YUVEffect *plugin, int x, int y);
00048 void create_objects();
00049 int close_event();
00050 YUVLevel *y, *u, *v;
00051 YUVEffect *plugin;
00052 };
00053
00054 PLUGIN_THREAD_HEADER(YUVEffect, YUVThread, YUVWindow)
00055
00056 class YUVEffect : public PluginVClient
00057 {
00058 public:
00059 YUVEffect(PluginServer *server);
00060 ~YUVEffect();
00061 int process_realtime(VFrame *input, VFrame *output);
00062 int is_realtime();
00063 char* plugin_title();
00064 VFrame* new_picon();
00065 int load_defaults();
00066 int save_defaults();
00067 void save_data(KeyFrame *keyframe);
00068 void read_data(KeyFrame *keyframe);
00069 void update_gui();
00070 int show_gui();
00071 void raise_window();
00072 int set_string();
00073 int load_configuration();
00074
00075 YUVConfig config;
00076 YUVThread *thread;
00077 BC_Hash *defaults;
00078 };
00079
00080
00081
00082
00083
00084 REGISTER_PLUGIN(YUVEffect)
00085
00086
00087
00088
00089
00090
00091
00092 YUVConfig::YUVConfig()
00093 {
00094 y = 0;
00095 u = 0;
00096 v = 0;
00097 }
00098
00099 void YUVConfig::copy_from(YUVConfig &src)
00100 {
00101 y = src.y;
00102 u = src.u;
00103 v = src.v;
00104 }
00105
00106 int YUVConfig::equivalent(YUVConfig &src)
00107 {
00108 return EQUIV(y, src.y) && EQUIV(u, src.u) && EQUIV(v, src.v);
00109 }
00110
00111 void YUVConfig::interpolate(YUVConfig &prev,
00112 YUVConfig &next,
00113 long prev_frame,
00114 long next_frame,
00115 long current_frame)
00116 {
00117 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
00118 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
00119
00120 y = prev.y * prev_scale + next.y * next_scale;
00121 u = prev.u * prev_scale + next.u * next_scale;
00122 v = prev.v * prev_scale + next.v * next_scale;
00123 }
00124
00125
00126
00127
00128
00129
00130 #define MAXVALUE 100
00131
00132 YUVLevel::YUVLevel(YUVEffect *plugin, float *output, int x, int y)
00133 : BC_FSlider(x,
00134 y,
00135 0,
00136 200,
00137 200,
00138 -MAXVALUE,
00139 MAXVALUE,
00140 *output)
00141 {
00142 this->plugin = plugin;
00143 this->output = output;
00144 }
00145
00146 int YUVLevel::handle_event()
00147 {
00148 *output = get_value();
00149 plugin->send_configure_change();
00150 return 1;
00151 }
00152
00153
00154 YUVWindow::YUVWindow(YUVEffect *plugin, int x, int y)
00155 : BC_Window(plugin->gui_string,
00156 x,
00157 y,
00158 260,
00159 100,
00160 260,
00161 100,
00162 0,
00163 0,
00164 1)
00165 {
00166 this->plugin = plugin;
00167 }
00168
00169 void YUVWindow::create_objects()
00170 {
00171 int x = 10, y = 10, x1 = 50;
00172 add_subwindow(new BC_Title(x, y, _("Y:")));
00173 add_subwindow(this->y = new YUVLevel(plugin, &plugin->config.y, x1, y));
00174 y += 30;
00175 add_subwindow(new BC_Title(x, y, _("U:")));
00176 add_subwindow(u = new YUVLevel(plugin, &plugin->config.u, x1, y));
00177 y += 30;
00178 add_subwindow(new BC_Title(x, y, _("V:")));
00179 add_subwindow(v = new YUVLevel(plugin, &plugin->config.v, x1, y));
00180
00181 show_window();
00182 flush();
00183 }
00184
00185 int YUVWindow::close_event()
00186 {
00187
00188 set_done(1);
00189 return 1;
00190 }
00191
00192
00193
00194
00195
00196 PLUGIN_THREAD_OBJECT(YUVEffect, YUVThread, YUVWindow)
00197
00198
00199
00200
00201
00202
00203 YUVEffect::YUVEffect(PluginServer *server)
00204 : PluginVClient(server)
00205 {
00206 PLUGIN_CONSTRUCTOR_MACRO
00207 }
00208 YUVEffect::~YUVEffect()
00209 {
00210 PLUGIN_DESTRUCTOR_MACRO
00211 }
00212
00213 char* YUVEffect::plugin_title() { return N_("YUV"); }
00214 int YUVEffect::is_realtime() { return 1; }
00215
00216
00217 NEW_PICON_MACRO(YUVEffect)
00218 SHOW_GUI_MACRO(YUVEffect, YUVThread)
00219 RAISE_WINDOW_MACRO(YUVEffect)
00220 SET_STRING_MACRO(YUVEffect)
00221 LOAD_CONFIGURATION_MACRO(YUVEffect, YUVConfig)
00222
00223 void YUVEffect::update_gui()
00224 {
00225 if(thread)
00226 {
00227 thread->window->lock_window();
00228 load_configuration();
00229 thread->window->y->update(config.y);
00230 thread->window->u->update(config.u);
00231 thread->window->v->update(config.v);
00232 thread->window->unlock_window();
00233 }
00234 }
00235
00236 int YUVEffect::load_defaults()
00237 {
00238 char directory[BCTEXTLEN];
00239 sprintf(directory, "%syuv.rc", BCASTDIR);
00240 defaults = new BC_Hash(directory);
00241 defaults->load();
00242 config.y = defaults->get("Y", config.y);
00243 config.u = defaults->get("U", config.u);
00244 config.v = defaults->get("V", config.v);
00245 return 0;
00246 }
00247
00248 int YUVEffect::save_defaults()
00249 {
00250 defaults->update("Y", config.y);
00251 defaults->update("U", config.u);
00252 defaults->update("V", config.v);
00253 defaults->save();
00254 return 0;
00255 }
00256
00257 void YUVEffect::save_data(KeyFrame *keyframe)
00258 {
00259 FileXML output;
00260 output.set_shared_string(keyframe->data, MESSAGESIZE);
00261 output.tag.set_title("YUV");
00262 output.tag.set_property("Y", config.y);
00263 output.tag.set_property("U", config.u);
00264 output.tag.set_property("V", config.v);
00265 output.append_tag();
00266 output.tag.set_title("/YUV");
00267 output.append_tag();
00268 output.terminate_string();
00269 }
00270
00271 void YUVEffect::read_data(KeyFrame *keyframe)
00272 {
00273 FileXML input;
00274 input.set_shared_string(keyframe->data, strlen(keyframe->data));
00275 while(!input.read_tag())
00276 {
00277 if(input.tag.title_is("YUV"))
00278 {
00279 config.y = input.tag.get_property("Y", config.y);
00280 config.u = input.tag.get_property("U", config.u);
00281 config.v = input.tag.get_property("V", config.v);
00282 }
00283 }
00284 }
00285
00286
00287 static YUV yuv_static;
00288
00289 #define YUV_MACRO(type, temp_type, max, components, use_yuv) \
00290 { \
00291 for(int i = 0; i < input->get_h(); i++) \
00292 { \
00293 type *in_row = (type*)input->get_rows()[i]; \
00294 type *out_row = (type*)output->get_rows()[i]; \
00295 const float round = (sizeof(type) == 4) ? 0.0 : 0.5; \
00296 \
00297 for(int j = 0; j < w; j++) \
00298 { \
00299 if(use_yuv) \
00300 { \
00301 int y = (int)((float)in_row[0] * y_scale + round); \
00302 int u = (int)((float)(in_row[1] - (max / 2 + 1)) * u_scale + round) + (max / 2 + 1); \
00303 int v = (int)((float)(in_row[2] - (max / 2 + 1)) * v_scale + round) + (max / 2 + 1); \
00304 out_row[0] = CLIP(y, 0, max); \
00305 out_row[1] = CLIP(u, 0, max); \
00306 out_row[2] = CLIP(v, 0, max); \
00307 } \
00308 else \
00309 { \
00310 temp_type y, u, v, r, g, b; \
00311 if(sizeof(type) == 4) \
00312 { \
00313 yuv_static.rgb_to_yuv_f(in_row[0], in_row[1], in_row[2], y, u, v); \
00314 } \
00315 else \
00316 if(sizeof(type) == 2) \
00317 { \
00318 yuv_static.rgb_to_yuv_16(in_row[0], in_row[1], in_row[2], y, u, v); \
00319 } \
00320 else \
00321 { \
00322 yuv_static.rgb_to_yuv_8(in_row[0], in_row[1], in_row[2], y, u, v); \
00323 } \
00324 \
00325 if(sizeof(type) < 4) \
00326 { \
00327 CLAMP(y, 0, max); \
00328 CLAMP(u, 0, max); \
00329 CLAMP(v, 0, max); \
00330 \
00331 y = temp_type((float)y * y_scale + round); \
00332 u = temp_type((float)(u - (max / 2 + 1)) * u_scale + round) + (max / 2 + 1); \
00333 v = temp_type((float)(v - (max / 2 + 1)) * v_scale + round) + (max / 2 + 1); \
00334 } \
00335 else \
00336 { \
00337 y = temp_type((float)y * y_scale + round); \
00338 u = temp_type((float)u * u_scale + round); \
00339 v = temp_type((float)v * v_scale + round); \
00340 } \
00341 \
00342 if(sizeof(type) == 4) \
00343 yuv_static.yuv_to_rgb_f(r, g, b, y, u, v); \
00344 else \
00345 if(sizeof(type) == 2) \
00346 yuv_static.yuv_to_rgb_16(r, g, b, y, u, v); \
00347 else \
00348 yuv_static.yuv_to_rgb_8(r, g, b, y, u, v); \
00349 \
00350 out_row[0] = r; \
00351 out_row[1] = g; \
00352 out_row[2] = b; \
00353 } \
00354 \
00355 in_row += components; \
00356 out_row += components; \
00357 } \
00358 } \
00359 }
00360
00361 int YUVEffect::process_realtime(VFrame *input, VFrame *output)
00362 {
00363 load_configuration();
00364
00365 if(EQUIV(config.y, 0) && EQUIV(config.u, 0) && EQUIV(config.v, 0))
00366 {
00367 if(input->get_rows()[0] != output->get_rows()[0])
00368 output->copy_from(input);
00369 }
00370 else
00371 {
00372 int w = input->get_w();
00373
00374 float y_scale = (float)(config.y + MAXVALUE) / MAXVALUE;
00375 float u_scale = (float)(config.u + MAXVALUE) / MAXVALUE;
00376 float v_scale = (float)(config.v + MAXVALUE) / MAXVALUE;
00377
00378 if(u_scale > 1) u_scale = 1 + (u_scale - 1) * 4;
00379 if(v_scale > 1) v_scale = 1 + (v_scale - 1) * 4;
00380
00381 switch(input->get_color_model())
00382 {
00383 case BC_RGB_FLOAT:
00384 YUV_MACRO(float, float, 1, 3, 0)
00385 break;
00386
00387 case BC_RGB888:
00388 YUV_MACRO(unsigned char, int, 0xff, 3, 0)
00389 break;
00390
00391 case BC_YUV888:
00392 YUV_MACRO(unsigned char, int, 0xff, 3, 1)
00393 break;
00394
00395 case BC_RGB161616:
00396 YUV_MACRO(uint16_t, int, 0xffff, 3, 0)
00397 break;
00398
00399 case BC_YUV161616:
00400 YUV_MACRO(uint16_t, int, 0xffff, 3, 1)
00401 break;
00402
00403 case BC_RGBA_FLOAT:
00404 YUV_MACRO(float, float, 1, 4, 0)
00405 break;
00406
00407 case BC_RGBA8888:
00408 YUV_MACRO(unsigned char, int, 0xff, 4, 0)
00409 break;
00410
00411 case BC_YUVA8888:
00412 YUV_MACRO(unsigned char, int, 0xff, 4, 1)
00413 break;
00414
00415 case BC_RGBA16161616:
00416 YUV_MACRO(uint16_t, int, 0xffff, 4, 0)
00417 break;
00418
00419 case BC_YUVA16161616:
00420 YUV_MACRO(uint16_t, int, 0xffff, 4, 1)
00421 break;
00422 }
00423
00424
00425
00426 }
00427 return 0;
00428 }
00429
00430