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 "loadbalance.h"
00008 #include "picon_png.h"
00009 #include "plugincolors.h"
00010 #include "pluginvclient.h"
00011 #include "fonts.h"
00012 #include "vframe.h"
00013
00014 #include <math.h>
00015 #include <stdint.h>
00016 #include <string.h>
00017 #include <assert.h>
00018
00019
00020
00021
00022 const float FLOAT_MIN = -0.1;
00023 const float FLOAT_MAX = 1.1;
00024 const int WAVEFORM_DIVISIONS = 12;
00025 const int VECTORSCOPE_DIVISIONS = 12;
00026 const int RGB_MIN = 48;
00027
00028
00029 const char LABEL_WIDTH_SAMPLE[] = "100 ";
00030 const int H_SPACE = 5;
00031 const int V_INSET = 10;
00032
00033
00034 const char WIDGET_HSPACE_SAMPLE[] = " ";
00035 const int WIDGET_VSPACE = 3;
00036
00037
00038
00039
00040
00041
00042
00043 const struct Vectorscope_HSV_axes
00044 {
00045 float hue;
00046 char label[4];
00047 int color;
00048 }
00049 Vectorscope_HSV_axes[] =
00050 {
00051 { 0, "R", RED },
00052 { 60, "Yl", YELLOW },
00053 { 120, "G", GREEN },
00054 { 180, "Cy", LTCYAN },
00055 { 240, "B", BLUE },
00056 { 300, "Mg", MDPURPLE },
00057 };
00058 const int Vectorscope_HSV_axes_count = sizeof(Vectorscope_HSV_axes) / sizeof(struct Vectorscope_HSV_axes);
00059
00060
00061
00062 class VideoScopeEffect;
00063 class VideoScopeEngine;
00064
00065
00066 class VideoScopeConfig
00067 {
00068 public:
00069 VideoScopeConfig();
00070 void reset();
00071
00072 int show_709_limits;
00073 int show_601_limits;
00074 int show_IRE_limits;
00075 int draw_lines_inverse;
00076 };
00077
00078 class VideoScopeGraduation
00079 {
00080
00081
00082 public:
00083 VideoScopeGraduation();
00084 void set(const char * label, int y);
00085
00086 char label[4];
00087 int y;
00088 };
00089
00090 class VideoScopeWaveform : public BC_SubWindow
00091 {
00092 public:
00093 VideoScopeWaveform(VideoScopeEffect *plugin,
00094 int x,
00095 int y,
00096 int w,
00097 int h);
00098 VideoScopeEffect *plugin;
00099
00100 void calculate_graduations();
00101 void draw_graduations();
00102 void redraw();
00103
00104
00105 static const int NUM_GRADS = WAVEFORM_DIVISIONS + 1;
00106 VideoScopeGraduation grads[NUM_GRADS];
00107
00108
00109
00110 int limit_IRE_black;
00111 int limit_601_white;
00112 int limit_601_black;
00113 };
00114
00115
00116 class VideoScopeVectorscope : public BC_SubWindow
00117 {
00118 public:
00119 VideoScopeVectorscope(VideoScopeEffect *plugin,
00120 int x,
00121 int y,
00122 int w,
00123 int h);
00124 VideoScopeEffect *plugin;
00125
00126 void calculate_graduations();
00127 void draw_graduations();
00128
00129
00130 static const int NUM_GRADS = VECTORSCOPE_DIVISIONS / 2;
00131 VideoScopeGraduation grads[NUM_GRADS];
00132
00133 private:
00134 int color_axis_font;
00135 struct {
00136 int x1, y1, x2, y2;
00137 int text_x, text_y;
00138 } axes[Vectorscope_HSV_axes_count];
00139 };
00140
00141 class VideoScopeShow709Limits : public BC_CheckBox
00142 {
00143 public:
00144 VideoScopeShow709Limits(VideoScopeEffect *plugin,
00145 int x,
00146 int y);
00147 int handle_event();
00148 VideoScopeEffect *plugin;
00149 };
00150
00151 class VideoScopeShow601Limits : public BC_CheckBox
00152 {
00153 public:
00154 VideoScopeShow601Limits(VideoScopeEffect *plugin,
00155 int x,
00156 int y);
00157 int handle_event();
00158 VideoScopeEffect *plugin;
00159 };
00160
00161 class VideoScopeShowIRELimits : public BC_CheckBox
00162 {
00163 public:
00164 VideoScopeShowIRELimits(VideoScopeEffect *plugin,
00165 int x,
00166 int y);
00167 int handle_event();
00168 VideoScopeEffect *plugin;
00169 };
00170
00171 class VideoScopeDrawLinesInverse : public BC_CheckBox
00172 {
00173 public:
00174 VideoScopeDrawLinesInverse(VideoScopeEffect *plugin,
00175 int x,
00176 int y);
00177 int handle_event();
00178 VideoScopeEffect *plugin;
00179 };
00180
00181 class VideoScopeWindow : public BC_Window
00182 {
00183 public:
00184 VideoScopeWindow(VideoScopeEffect *plugin, int x, int y);
00185 ~VideoScopeWindow();
00186
00187 void calculate_sizes(int w, int h);
00188 int get_label_width();
00189 int get_widget_area_height();
00190 void create_objects();
00191 int close_event();
00192 int resize_event(int w, int h);
00193 void allocate_bitmaps();
00194 void draw_labels();
00195
00196 VideoScopeEffect *plugin;
00197 VideoScopeWaveform *waveform;
00198 VideoScopeVectorscope *vectorscope;
00199 VideoScopeShow709Limits *show_709_limits;
00200 VideoScopeShow601Limits *show_601_limits;
00201 VideoScopeShowIRELimits *show_IRE_limits;
00202 VideoScopeDrawLinesInverse *draw_lines_inverse;
00203 BC_Bitmap *waveform_bitmap;
00204 BC_Bitmap *vector_bitmap;
00205
00206 int vector_x, vector_y, vector_w, vector_h;
00207 int wave_x, wave_y, wave_w, wave_h;
00208 };
00209
00210 PLUGIN_THREAD_HEADER(VideoScopeEffect, VideoScopeThread, VideoScopeWindow)
00211
00212
00213
00214
00215 class VideoScopePackage : public LoadPackage
00216 {
00217 public:
00218 VideoScopePackage();
00219 int row1, row2;
00220 };
00221
00222
00223 class VideoScopeUnit : public LoadClient
00224 {
00225 public:
00226 VideoScopeUnit(VideoScopeEffect *plugin, VideoScopeEngine *server);
00227 void process_package(LoadPackage *package);
00228 VideoScopeEffect *plugin;
00229 YUV yuv;
00230 private:
00231 template<typename TYPE, typename TEMP_TYPE,
00232 int MAX, int COMPONENTS, bool USE_YUV>
00233 void render_data(LoadPackage *package);
00234 };
00235
00236 class VideoScopeEngine : public LoadServer
00237 {
00238 public:
00239 VideoScopeEngine(VideoScopeEffect *plugin, int cpus);
00240 ~VideoScopeEngine();
00241 void init_packages();
00242 LoadClient* new_client();
00243 LoadPackage* new_package();
00244 VideoScopeEffect *plugin;
00245 };
00246
00247 class VideoScopeEffect : public PluginVClient
00248 {
00249 public:
00250 VideoScopeEffect(PluginServer *server);
00251 ~VideoScopeEffect();
00252
00253 int process_realtime(VFrame *input, VFrame *output);
00254 int is_realtime();
00255 char* plugin_title();
00256 VFrame* new_picon();
00257 int load_defaults();
00258 int save_defaults();
00259 void save_data(KeyFrame *keyframe);
00260 void read_data(KeyFrame *keyframe);
00261 int show_gui();
00262 int set_string();
00263 void raise_window();
00264 void render_gui(void *input);
00265 int load_configuration();
00266
00267 int w, h;
00268 VFrame *input;
00269 VideoScopeConfig config;
00270 VideoScopeEngine *engine;
00271 BC_Hash *defaults;
00272 VideoScopeThread *thread;
00273 };
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287 VideoScopeConfig::VideoScopeConfig()
00288 {
00289 reset();
00290 }
00291
00292 void VideoScopeConfig::reset()
00293 {
00294 show_709_limits = 0;
00295 show_601_limits = 0;
00296 show_IRE_limits = 0;
00297 draw_lines_inverse = 0;
00298 }
00299
00300
00301
00302
00303
00304
00305
00306
00307 VideoScopeWaveform::VideoScopeWaveform(VideoScopeEffect *plugin,
00308 int x,
00309 int y,
00310 int w,
00311 int h)
00312 : BC_SubWindow(x, y, w, h, BLACK)
00313 {
00314 this->plugin = plugin;
00315 }
00316
00317
00318 VideoScopeVectorscope::VideoScopeVectorscope(VideoScopeEffect *plugin,
00319 int x,
00320 int y,
00321 int w,
00322 int h)
00323 : BC_SubWindow(x, y, w, h, BLACK)
00324 {
00325 this->plugin = plugin;
00326 }
00327
00328
00329
00330
00331 VideoScopeWindow::VideoScopeWindow(VideoScopeEffect *plugin,
00332 int x,
00333 int y)
00334 : BC_Window(plugin->gui_string,
00335 x,
00336 y,
00337 plugin->w,
00338 plugin->h,
00339 50,
00340 50,
00341 1,
00342 0,
00343 1,
00344 BLACK)
00345 {
00346 this->plugin = plugin;
00347 waveform_bitmap = 0;
00348 vector_bitmap = 0;
00349 }
00350
00351 VideoScopeWindow::~VideoScopeWindow()
00352 {
00353 if(waveform_bitmap) delete waveform_bitmap;
00354 if(vector_bitmap) delete vector_bitmap;
00355 }
00356
00357 VideoScopeGraduation::VideoScopeGraduation()
00358 {
00359 bzero(label, sizeof(label));
00360 }
00361
00362 void VideoScopeWindow::calculate_sizes(int w, int h)
00363 {
00364 const int w_midpoint = w / 2;
00365 const int label_width = get_label_width();
00366
00367
00368
00369 wave_x = label_width + H_SPACE;
00370 wave_y = V_INSET;
00371 wave_w = w_midpoint - H_SPACE - wave_x;
00372 wave_h = h - V_INSET - wave_y;
00373
00374
00375
00376 const int vec_max_width = w_midpoint - H_SPACE - label_width;
00377 const int vec_max_height = h - 2 * V_INSET;
00378 const int square = MIN(vec_max_width, vec_max_height);
00379 vector_x = w_midpoint + label_width + (w_midpoint - square- H_SPACE - label_width) / 2;
00380 vector_y = (h - square) / 2;
00381 vector_w = square;
00382 vector_h = square;
00383 }
00384
00385 int VideoScopeWindow::get_label_width()
00386 {
00387 return get_text_width(SMALLFONT, (char *) LABEL_WIDTH_SAMPLE);
00388 }
00389
00390 int VideoScopeWindow::get_widget_area_height()
00391 {
00392
00393
00394
00395 return 2 * get_text_height(MEDIUMFONT, (char *) WIDGET_HSPACE_SAMPLE);
00396 }
00397
00398 void VideoScopeWindow::create_objects()
00399 {
00400 int w = get_w();
00401 int h = get_h();
00402
00403
00404 const int widget_hspace = get_text_width(MEDIUMFONT, (char *) WIDGET_HSPACE_SAMPLE);
00405 const int widget_height = get_widget_area_height();
00406 int x = widget_hspace;
00407 int y = h - widget_height + WIDGET_VSPACE;
00408 set_color(get_resources()->get_bg_color());
00409 draw_box(0, h - widget_height, w, widget_height);
00410 add_subwindow(show_709_limits = new VideoScopeShow709Limits(plugin, x, y));
00411 x += show_709_limits->get_w() + widget_hspace;
00412 add_subwindow(show_601_limits = new VideoScopeShow601Limits(plugin, x, y));
00413 x += show_601_limits->get_w() + widget_hspace;
00414 add_subwindow(show_IRE_limits = new VideoScopeShowIRELimits(plugin, x, y));
00415 x += show_IRE_limits->get_w() + widget_hspace;
00416 add_subwindow(draw_lines_inverse = new VideoScopeDrawLinesInverse(plugin, x, y));
00417
00418 calculate_sizes(w, h - widget_height - WIDGET_VSPACE);
00419
00420 add_subwindow(waveform = new VideoScopeWaveform(plugin,
00421 wave_x,
00422 wave_y,
00423 wave_w,
00424 wave_h));
00425 add_subwindow(vectorscope = new VideoScopeVectorscope(plugin,
00426 vector_x,
00427 vector_y,
00428 vector_w,
00429 vector_h));
00430 allocate_bitmaps();
00431
00432 waveform->calculate_graduations();
00433 vectorscope->calculate_graduations();
00434 waveform->draw_graduations();
00435 vectorscope->draw_graduations();
00436 draw_labels();
00437
00438 show_window();
00439 flush();
00440
00441 }
00442
00443 WINDOW_CLOSE_EVENT(VideoScopeWindow)
00444
00445 int VideoScopeWindow::resize_event(int w, int h)
00446 {
00447 const int widget_height = get_widget_area_height();
00448
00449 clear_box(0, 0, w, h);
00450 plugin->w = w;
00451 plugin->h = h;
00452 calculate_sizes(w, h - widget_height - WIDGET_VSPACE);
00453 waveform->reposition_window(wave_x, wave_y, wave_w, wave_h);
00454 vectorscope->reposition_window(vector_x, vector_y, vector_w, vector_h);
00455 waveform->clear_box(0, 0, wave_w, wave_h);
00456 vectorscope->clear_box(0, 0, vector_w, vector_h);
00457 allocate_bitmaps();
00458
00459 int y = h - widget_height + WIDGET_VSPACE;
00460 set_color(get_resources()->get_bg_color());
00461 draw_box(0, h - widget_height, w, widget_height);
00462 show_709_limits->reposition_window(show_709_limits->get_x(), y);
00463 show_601_limits->reposition_window(show_601_limits->get_x(), y);
00464 show_IRE_limits->reposition_window(show_IRE_limits->get_x(), y);
00465 draw_lines_inverse->reposition_window(draw_lines_inverse->get_x(), y);
00466
00467 waveform->calculate_graduations();
00468 vectorscope->calculate_graduations();
00469 waveform->draw_graduations();
00470 vectorscope->draw_graduations();
00471 draw_labels();
00472
00473 flash();
00474
00475 return 1;
00476 }
00477
00478 void VideoScopeWaveform::redraw()
00479 {
00480 clear_box(0, 0, get_w(), get_h());
00481 draw_graduations();
00482 flash();
00483 }
00484
00485 void VideoScopeWindow::allocate_bitmaps()
00486 {
00487 if(waveform_bitmap) delete waveform_bitmap;
00488 if(vector_bitmap) delete vector_bitmap;
00489
00490 waveform_bitmap = new_bitmap(wave_w, wave_h);
00491 vector_bitmap = new_bitmap(vector_w, vector_h);
00492 }
00493
00494
00495
00496
00497 static void polar_to_cartesian(float h,
00498 float s,
00499 float radius,
00500 int & x,
00501 int & y)
00502 {
00503 float adjacent = cos(h / 360 * 2 * M_PI);
00504 float opposite = sin(h / 360 * 2 * M_PI);
00505 float r = (s - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN) * radius;
00506 x = (int)roundf(radius + adjacent * r);
00507 y = (int)roundf(radius - opposite * r);
00508 }
00509
00510
00511 void VideoScopeWaveform::calculate_graduations()
00512 {
00513 int height = get_h();
00514
00515 for(int i = 0; i <= WAVEFORM_DIVISIONS; i++)
00516 {
00517 int y = height * i / WAVEFORM_DIVISIONS;
00518 char string[BCTEXTLEN];
00519 sprintf(string, "%d",
00520 (int)round((FLOAT_MAX -
00521 i * (FLOAT_MAX - FLOAT_MIN) / WAVEFORM_DIVISIONS) * 100));
00522 grads[i].set(string, CLAMP(y, 0, height - 1));
00523 }
00524
00525
00526 limit_IRE_black = (int)round(height * (FLOAT_MAX - 0.075) / (FLOAT_MAX - FLOAT_MIN));
00527 limit_601_white = (int)round(height * (FLOAT_MAX - 235.0/255.0) / (FLOAT_MAX - FLOAT_MIN));
00528 limit_601_black = (int)round(height * (FLOAT_MAX - 16.0/255.0) / (FLOAT_MAX - FLOAT_MIN));
00529 }
00530
00531
00532 void VideoScopeVectorscope::calculate_graduations()
00533 {
00534
00535 const int radius = get_h() / 2;
00536 for(int i = 1, g = 0; i <= VECTORSCOPE_DIVISIONS - 1; i += 2)
00537 {
00538 int y = radius - radius * i / VECTORSCOPE_DIVISIONS;
00539 char string[BCTEXTLEN];
00540 sprintf(string, "%d",
00541 (int)round((FLOAT_MIN +
00542 (FLOAT_MAX - FLOAT_MIN) / VECTORSCOPE_DIVISIONS * i) * 100));
00543 grads[g++].set(string, y);
00544 }
00545
00546
00547 color_axis_font = radius > 200 ? MEDIUMFONT : SMALLFONT;
00548 const int ascent_half = get_text_ascent(color_axis_font) / 2;
00549 for (int i = 0; i < Vectorscope_HSV_axes_count; ++i)
00550 {
00551 const float hue = Vectorscope_HSV_axes[i].hue;
00552 polar_to_cartesian(hue, 0, radius, axes[i].x1, axes[i].y1);
00553 polar_to_cartesian(hue, 1, radius, axes[i].x2, axes[i].y2);
00554
00555
00556
00557
00558
00559
00560 polar_to_cartesian(hue, 1 + (FLOAT_MAX - 1) / 2, radius, axes[i].text_x, axes[i].text_y);
00561 axes[i].text_x -= get_text_width(color_axis_font, const_cast<char *>(Vectorscope_HSV_axes[i].label)) / 2;
00562 axes[i].text_y += ascent_half;
00563 }
00564 }
00565
00566 void VideoScopeWindow::draw_labels()
00567 {
00568 set_color(LTGREY);
00569 set_font(SMALLFONT);
00570 const int sm_text_ascent_half = get_text_ascent(SMALLFONT) / 2;
00571 const int label_width_half = get_label_width() / 2;
00572
00573
00574 if (waveform) {
00575 const int text_x = wave_x - label_width_half;
00576 for (int i = 0; i < VideoScopeWaveform::NUM_GRADS; ++i)
00577 draw_center_text(text_x,
00578 waveform->grads[i].y + wave_y + sm_text_ascent_half,
00579 waveform->grads[i].label);
00580
00581 }
00582
00583
00584 if (vectorscope) {
00585 const int text_x = vector_x - label_width_half;
00586 for (int i = 0; i < VideoScopeVectorscope::NUM_GRADS; ++i)
00587 draw_center_text(text_x,
00588 vectorscope->grads[i].y + vector_y + sm_text_ascent_half,
00589 vectorscope->grads[i].label);
00590 }
00591
00592 #ifdef DEBUG_PLACEMENT
00593 set_color(GREEN);
00594 draw_rectangle(wave_x - 2 * label_width_half, wave_y - sm_text_ascent_half,
00595 2 * label_width_half, wave_h + 2 * sm_text_ascent_half);
00596 draw_rectangle(vector_x - 2 * label_width_half, vector_y,
00597 2 * label_width_half, vector_h);
00598 set_color(BLUE);
00599 waveform->draw_rectangle(0, 0, wave_w, wave_h);
00600 set_color(RED);
00601 vectorscope->draw_rectangle(0, 0, vector_w, vector_h);
00602 #endif // DEBUG_PLACEMENT
00603
00604 set_font(MEDIUMFONT);
00605 waveform->flash();
00606 vectorscope->flash();
00607 flush();
00608 }
00609
00610
00611 void VideoScopeWaveform::draw_graduations()
00612 {
00613 VideoScopeConfig &config = plugin->config;
00614 if (config.draw_lines_inverse) set_inverse();
00615 const int w = get_w();
00616 const int h = get_h();
00617 for (int i = 0; i < NUM_GRADS; ++i)
00618 {
00619
00620 set_color((config.show_709_limits && (i == 1 || i == 11))
00621 ? WHITE : MDGREY);
00622 int y = grads[i].y;
00623 draw_line(0, y, w, y);
00624 }
00625 if (config.show_601_limits)
00626 {
00627 set_color(WHITE);
00628 draw_line(0, limit_601_white, w, limit_601_white);
00629 draw_line(0, limit_601_black, w, limit_601_black);
00630 }
00631 if (config.show_IRE_limits)
00632 {
00633 set_color(WHITE);
00634 draw_line(0, limit_IRE_black, w, limit_IRE_black);
00635 }
00636 if (config.draw_lines_inverse) set_opaque();
00637 }
00638
00639 void VideoScopeVectorscope::draw_graduations()
00640 {
00641 set_color(MDGREY);
00642 const int diameter = get_h();
00643 for (int i = 0; i < NUM_GRADS; ++i)
00644 {
00645 int top_left = grads[i].y;
00646 int width_height = diameter - 2 * top_left;
00647 draw_circle(top_left, top_left, width_height, width_height);
00648 }
00649
00650
00651 set_font(color_axis_font);
00652 for (int i = 0; i < Vectorscope_HSV_axes_count; ++i)
00653 {
00654 set_color(MDGREY);
00655 draw_line(axes[i].x1, axes[i].y1,
00656 axes[i].x2, axes[i].y2);
00657
00658 set_color(Vectorscope_HSV_axes[i].color);
00659 draw_text(axes[i].text_x, axes[i].text_y, const_cast<char *>(Vectorscope_HSV_axes[i].label));
00660
00661 #ifdef DEBUG_PLACEMENT
00662 int label_w = get_text_width(color_axis_font, const_cast<char *>(Vectorscope_HSV_axes[i].label));
00663 int label_a = get_text_ascent(color_axis_font);
00664 int label_d = get_text_descent(color_axis_font);
00665 draw_rectangle(axes[i].text_x,
00666 axes[i].text_y - label_a,
00667 label_w, label_a + label_d);
00668 #endif // DEBUG_PLACEMENT
00669 }
00670 }
00671
00672 void VideoScopeGraduation::set(const char * label, int y)
00673 {
00674 assert(strlen(label) <= 3);
00675 strcpy(this->label, label);
00676 this->y = y;
00677 }
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687 VideoScopeShow709Limits::VideoScopeShow709Limits(VideoScopeEffect *plugin,
00688 int x,
00689 int y)
00690 : BC_CheckBox(x, y, plugin->config.show_709_limits, _("HDTV"))
00691 {
00692 this->plugin = plugin;
00693 set_tooltip("Indicate ITU-R BT.709 limits. Use when rendering to HDTV and sRGB.");
00694 }
00695
00696 int VideoScopeShow709Limits::handle_event()
00697 {
00698 plugin->config.show_709_limits = get_value();
00699 plugin->thread->window->waveform->redraw();
00700 return 1;
00701 }
00702
00703 VideoScopeShow601Limits::VideoScopeShow601Limits(VideoScopeEffect *plugin,
00704 int x,
00705 int y)
00706 : BC_CheckBox(x, y, plugin->config.show_601_limits, _("MPEG"))
00707 {
00708 this->plugin = plugin;
00709 set_tooltip("Indicate ITU-R BT.601 limits. Use when rendering to analog video and MPEG.");
00710 }
00711
00712 int VideoScopeShow601Limits::handle_event()
00713 {
00714 plugin->config.show_601_limits = get_value();
00715 plugin->thread->window->waveform->redraw();
00716 return 1;
00717 }
00718
00719 VideoScopeShowIRELimits::VideoScopeShowIRELimits(VideoScopeEffect *plugin,
00720 int x,
00721 int y)
00722 : BC_CheckBox(x, y, plugin->config.show_IRE_limits, _("NTSC"))
00723 {
00724 this->plugin = plugin;
00725 set_tooltip("Indicate IRE 7.5% black level.");
00726 }
00727
00728 int VideoScopeShowIRELimits::handle_event()
00729 {
00730 plugin->config.show_IRE_limits = get_value();
00731 plugin->thread->window->waveform->redraw();
00732 return 1;
00733 }
00734
00735 VideoScopeDrawLinesInverse::VideoScopeDrawLinesInverse(VideoScopeEffect *plugin,
00736 int x,
00737 int y)
00738 : BC_CheckBox(x, y, plugin->config.draw_lines_inverse, _("Inverse"))
00739 {
00740 this->plugin = plugin;
00741 set_tooltip("Draw graduation lines so points underneath are visible");
00742 }
00743
00744 int VideoScopeDrawLinesInverse::handle_event()
00745 {
00746 plugin->config.draw_lines_inverse = get_value();
00747 plugin->thread->window->waveform->redraw();
00748 return 1;
00749 }
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759 PLUGIN_THREAD_OBJECT(VideoScopeEffect, VideoScopeThread, VideoScopeWindow)
00760
00761
00762
00763
00764
00765 REGISTER_PLUGIN(VideoScopeEffect)
00766
00767
00768
00769
00770
00771
00772 VideoScopeEffect::VideoScopeEffect(PluginServer *server)
00773 : PluginVClient(server)
00774 {
00775 engine = 0;
00776 w = 640;
00777 h = 260;
00778 PLUGIN_CONSTRUCTOR_MACRO
00779 }
00780
00781 VideoScopeEffect::~VideoScopeEffect()
00782 {
00783 PLUGIN_DESTRUCTOR_MACRO
00784
00785 if(engine) delete engine;
00786 }
00787
00788
00789
00790 char* VideoScopeEffect::plugin_title() { return N_("VideoScope"); }
00791 int VideoScopeEffect::is_realtime() { return 1; }
00792
00793 int VideoScopeEffect::load_configuration()
00794 {
00795 return 0;
00796 }
00797
00798 NEW_PICON_MACRO(VideoScopeEffect)
00799
00800 SHOW_GUI_MACRO(VideoScopeEffect, VideoScopeThread)
00801
00802 RAISE_WINDOW_MACRO(VideoScopeEffect)
00803
00804 SET_STRING_MACRO(VideoScopeEffect)
00805
00806 int VideoScopeEffect::load_defaults()
00807 {
00808 char directory[BCTEXTLEN];
00809
00810 sprintf(directory, "%svideoscope.rc", BCASTDIR);
00811
00812
00813 defaults = new BC_Hash(directory);
00814 defaults->load();
00815
00816 w = defaults->get("W", w);
00817 h = defaults->get("H", h);
00818 config.show_709_limits = defaults->get("SHOW_709_LIMITS", config.show_709_limits);
00819 config.show_601_limits = defaults->get("SHOW_601_LIMITS", config.show_601_limits);
00820 config.show_IRE_limits = defaults->get("SHOW_IRE_LIMITS", config.show_IRE_limits);
00821 config.draw_lines_inverse = defaults->get("DRAW_LINES_INVERSE", config.draw_lines_inverse);
00822
00823 return 0;
00824 }
00825
00826 int VideoScopeEffect::save_defaults()
00827 {
00828 defaults->update("W", w);
00829 defaults->update("H", h);
00830 defaults->update("SHOW_709_LIMITS", config.show_709_limits);
00831 defaults->update("SHOW_601_LIMITS", config.show_601_limits);
00832 defaults->update("SHOW_IRE_LIMITS", config.show_IRE_limits);
00833 defaults->update("DRAW_LINES_INVERSE", config.draw_lines_inverse);
00834 defaults->save();
00835 return 0;
00836 }
00837
00838 void VideoScopeEffect::save_data(KeyFrame *keyframe)
00839 {
00840 FileXML file;
00841 file.set_shared_string(keyframe->data, MESSAGESIZE);
00842 file.tag.set_title("VIDEOSCOPE");
00843 file.tag.set_property("SHOW_709_LIMITS", config.show_709_limits);
00844 file.tag.set_property("SHOW_601_LIMITS", config.show_601_limits);
00845 file.tag.set_property("SHOW_IRE_LIMITS", config.show_IRE_limits);
00846 file.tag.set_property("DRAW_LINES_INVERSE", config.draw_lines_inverse);
00847 file.append_tag();
00848 file.tag.set_title("/VIDEOSCOPE");
00849 file.append_tag();
00850 file.terminate_string();
00851 }
00852
00853 void VideoScopeEffect::read_data(KeyFrame *keyframe)
00854 {
00855 FileXML file;
00856 file.set_shared_string(keyframe->data, strlen(keyframe->data));
00857 int result = 0;
00858 while(!result)
00859 {
00860 result = file.read_tag();
00861 if(!result)
00862 {
00863 config.show_709_limits = file.tag.get_property("SHOW_709_LIMITS", config.show_709_limits);
00864 config.show_601_limits = file.tag.get_property("SHOW_601_LIMITS", config.show_601_limits);
00865 config.show_IRE_limits = file.tag.get_property("SHOW_IRE_LIMITS", config.show_IRE_limits);
00866 config.draw_lines_inverse = file.tag.get_property("DRAW_LINES_INVERSE", config.draw_lines_inverse);
00867 }
00868 }
00869 }
00870
00871 int VideoScopeEffect::process_realtime(VFrame *input, VFrame *output)
00872 {
00873
00874 send_render_gui(input);
00875
00876 if(input->get_rows()[0] != output->get_rows()[0])
00877 output->copy_from(input);
00878 return 1;
00879 }
00880
00881 void VideoScopeEffect::render_gui(void *input)
00882 {
00883 if(thread)
00884 {
00885 VideoScopeWindow *window = thread->window;
00886 window->lock_window();
00887
00888
00889 this->input = (VFrame*)input;
00890
00891
00892
00893 if(!engine)
00894 {
00895 engine = new VideoScopeEngine(this,
00896 (PluginClient::smp + 1));
00897 }
00898
00899
00900
00901 bzero(window->waveform_bitmap->get_data(),
00902 window->waveform_bitmap->get_h() *
00903 window->waveform_bitmap->get_bytes_per_line());
00904 bzero(window->vector_bitmap->get_data(),
00905 window->vector_bitmap->get_h() *
00906 window->vector_bitmap->get_bytes_per_line());
00907
00908 engine->process_packages();
00909
00910
00911
00912 window->waveform->draw_bitmap(window->waveform_bitmap,
00913 1,
00914 0,
00915 0);
00916
00917
00918 window->vectorscope->draw_bitmap(window->vector_bitmap,
00919 1,
00920 0,
00921 0);
00922
00923
00924 window->waveform->draw_graduations();
00925 window->vectorscope->draw_graduations();
00926 window->waveform->flash();
00927 window->vectorscope->flash();
00928
00929
00930 window->unlock_window();
00931 }
00932 }
00933
00934
00935
00936
00937
00938 VideoScopePackage::VideoScopePackage()
00939 : LoadPackage()
00940 {
00941 }
00942
00943
00944
00945
00946
00947
00948 VideoScopeUnit::VideoScopeUnit(VideoScopeEffect *plugin,
00949 VideoScopeEngine *server)
00950 : LoadClient(server)
00951 {
00952 this->plugin = plugin;
00953 }
00954
00955
00956 static void draw_point(unsigned char **rows,
00957 int color_model,
00958 int x,
00959 int y,
00960 int r,
00961 int g,
00962 int b)
00963 {
00964 switch(color_model)
00965 {
00966 case BC_BGR8888:
00967 {
00968 unsigned char *pixel = rows[y] + x * 4;
00969 pixel[0] = b;
00970 pixel[1] = g;
00971 pixel[2] = r;
00972 break;
00973 }
00974 case BC_BGR888:
00975 break;
00976 case BC_RGB565:
00977 {
00978 unsigned char *pixel = rows[y] + x * 2;
00979 pixel[0] = (r & 0xf8) | (g >> 5);
00980 pixel[1] = ((g & 0xfc) << 5) | (b >> 3);
00981 break;
00982 }
00983 case BC_BGR565:
00984 break;
00985 case BC_RGB8:
00986 break;
00987 }
00988 }
00989
00990
00991
00992
00993
00994 static int brighten(int v)
00995 {
00996 return (((256 - RGB_MIN) * v) + (256 * RGB_MIN))/256;
00997 }
00998
00999
01000
01001 template<typename TYPE, typename TEMP_TYPE, int MAX, int COMPONENTS, bool USE_YUV>
01002 void VideoScopeUnit::render_data(LoadPackage *package)
01003 {
01004 VideoScopeWindow *window = plugin->thread->window;
01005 VideoScopePackage *pkg = (VideoScopePackage*)package;
01006 int w = plugin->input->get_w();
01007 int h = plugin->input->get_h();
01008 int waveform_h = window->wave_h;
01009 int waveform_w = window->wave_w;
01010 int waveform_cmodel = window->waveform_bitmap->get_color_model();
01011 unsigned char **waveform_rows = window->waveform_bitmap->get_row_pointers();
01012 int vector_h = window->vector_bitmap->get_h();
01013 int vector_w = window->vector_bitmap->get_w();
01014 int vector_cmodel = window->vector_bitmap->get_color_model();
01015 unsigned char **vector_rows = window->vector_bitmap->get_row_pointers();
01016 float radius = vector_h / 2.0;
01017
01018 for(int i = pkg->row1; i < pkg->row2; i++)
01019 {
01020 TYPE *in_row = (TYPE*)plugin->input->get_rows()[i];
01021 for(int j = 0; j < w; j++)
01022 {
01023 TYPE *in_pixel = in_row + j * COMPONENTS;
01024 float intensity;
01025
01026
01027 if(USE_YUV) intensity = (float)*in_pixel / MAX;
01028
01029 float h, s, v;
01030 TEMP_TYPE r, g, b;
01031 if(USE_YUV)
01032 {
01033 if(sizeof(TYPE) == 2)
01034 {
01035 yuv.yuv_to_rgb_16(r,
01036 g,
01037 b,
01038 in_pixel[0],
01039 in_pixel[1],
01040 in_pixel[2]);
01041 }
01042 else
01043 {
01044 yuv.yuv_to_rgb_8(r,
01045 g,
01046 b,
01047 in_pixel[0],
01048 in_pixel[1],
01049 in_pixel[2]);
01050 }
01051 }
01052 else
01053 {
01054 r = in_pixel[0];
01055 g = in_pixel[1];
01056 b = in_pixel[2];
01057 }
01058
01059 HSV::rgb_to_hsv((float)r / MAX,
01060 (float)g / MAX,
01061 (float)b / MAX,
01062 h,
01063 s,
01064 v);
01065
01066
01067 int ri, gi, bi;
01068 if(sizeof(TYPE) == 2)
01069 {
01070 ri = (int)(r/256);
01071 gi = (int)(g/256);
01072 bi = (int)(b/256);
01073 }
01074 else
01075 if(sizeof(TYPE) == 4)
01076 {
01077 ri = (int)(CLIP(r, 0, 1) * 0xff);
01078 gi = (int)(CLIP(g, 0, 1) * 0xff);
01079 bi = (int)(CLIP(b, 0, 1) * 0xff);
01080 }
01081 else
01082 {
01083 ri = (int)r;
01084 gi = (int)g;
01085 bi = (int)b;
01086 }
01087
01088
01089 ri = brighten(ri);
01090 gi = brighten(gi);
01091 bi = brighten(bi);
01092
01093
01094 if(!USE_YUV) intensity = v;
01095 int y = waveform_h -
01096 (int)roundf((intensity - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN) *
01097 waveform_h);
01098 int x = j * waveform_w / w;
01099 if(x >= 0 && x < waveform_w && y >= 0 && y < waveform_h)
01100 draw_point(waveform_rows,
01101 waveform_cmodel,
01102 x,
01103 y,
01104 ri,
01105 gi,
01106 bi);
01107
01108
01109 polar_to_cartesian(h, s, radius, x, y);
01110 CLAMP(x, 0, vector_w - 1);
01111 CLAMP(y, 0, vector_h - 1);
01112 draw_point(vector_rows,
01113 vector_cmodel,
01114 x,
01115 y,
01116 ri,
01117 gi,
01118 bi);
01119 }
01120 }
01121 }
01122
01123
01124
01125 void VideoScopeUnit::process_package(LoadPackage *package)
01126 {
01127 switch(plugin->input->get_color_model())
01128 {
01129 case BC_RGB888:
01130 render_data<unsigned char, int, 0xff, 3, 0>(package);
01131 break;
01132
01133 case BC_RGB_FLOAT:
01134 render_data<float, float, 1, 3, 0>(package);
01135 break;
01136
01137 case BC_YUV888:
01138 render_data<unsigned char, int, 0xff, 3, 1>(package);
01139 break;
01140
01141 case BC_RGB161616:
01142 render_data<uint16_t, int, 0xffff, 3, 0>(package);
01143 break;
01144
01145 case BC_YUV161616:
01146 render_data<uint16_t, int, 0xffff, 3, 1>(package);
01147 break;
01148
01149 case BC_RGBA8888:
01150 render_data<unsigned char, int, 0xff, 4, 0>(package);
01151 break;
01152
01153 case BC_RGBA_FLOAT:
01154 render_data<float, float, 1, 4, 0>(package);
01155 break;
01156
01157 case BC_YUVA8888:
01158 render_data<unsigned char, int, 0xff, 4, 1>(package);
01159 break;
01160
01161 case BC_RGBA16161616:
01162 render_data<uint16_t, int, 0xffff, 4, 0>(package);
01163 break;
01164
01165 case BC_YUVA16161616:
01166 render_data<uint16_t, int, 0xffff, 4, 1>(package);
01167 break;
01168 }
01169 }
01170
01171
01172
01173
01174
01175
01176 VideoScopeEngine::VideoScopeEngine(VideoScopeEffect *plugin, int cpus)
01177 : LoadServer(cpus, cpus)
01178 {
01179 this->plugin = plugin;
01180 }
01181
01182 VideoScopeEngine::~VideoScopeEngine()
01183 {
01184 }
01185
01186 void VideoScopeEngine::init_packages()
01187 {
01188 for(int i = 0; i < LoadServer::get_total_packages(); i++)
01189 {
01190 VideoScopePackage *pkg = (VideoScopePackage*)get_package(i);
01191 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
01192 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
01193 }
01194 }
01195
01196
01197 LoadClient* VideoScopeEngine::new_client()
01198 {
01199 return new VideoScopeUnit(plugin, this);
01200 }
01201
01202 LoadPackage* VideoScopeEngine::new_package()
01203 {
01204 return new VideoScopePackage;
01205 }
01206