r373: Merged the official release 1.2.1.
[cinelerra_cv.git] / plugins / videoscope / videoscope.C
blobd49b2aefdf875800ac9143364c533a619b89ca6c
1 #include "bcdisplayinfo.h"
2 #include "clip.h"
3 #include "defaults.h"
4 #include "filexml.h"
5 #include "guicast.h"
6 #include "language.h"
7 #include "loadbalance.h"
8 #include "picon_png.h"
9 #include "plugincolors.h"
10 #include "pluginvclient.h"
11 #include "fonts.h"
12 #include "vframe.h"
14 #include <math.h>
15 #include <stdint.h>
16 #include <string.h>
21 #define FLOAT_MIN -0.1
22 #define FLOAT_MAX 1.1
23 #define WAVEFORM_DIVISIONS 12
24 #define VECTORSCOPE_DIVISIONS 12
27 class VideoScopeEffect;
28 class VideoScopeEngine;
31 class VideoScopeConfig
33 public:
34         VideoScopeConfig();
37 class VideoScopeWaveform : public BC_SubWindow
39 public:
40         VideoScopeWaveform(VideoScopeEffect *plugin, 
41                 int x, 
42                 int y,
43                 int w,
44                 int h);
45         VideoScopeEffect *plugin;
49 class VideoScopeVectorscope : public BC_SubWindow
51 public:
52         VideoScopeVectorscope(VideoScopeEffect *plugin, 
53                 int x, 
54                 int y,
55                 int w,
56                 int h);
57         VideoScopeEffect *plugin;
60 class VideoScopeWindow : public BC_Window
62 public:
63         VideoScopeWindow(VideoScopeEffect *plugin, int x, int y);
64         ~VideoScopeWindow();
66         void calculate_sizes(int w, int h);
67         void create_objects();
68         int close_event();
69         int resize_event(int w, int h);
70         void allocate_bitmaps();
71         void draw_overlays();
73         VideoScopeEffect *plugin;
74         VideoScopeWaveform *waveform;
75         VideoScopeVectorscope *vectorscope;
76         BC_Bitmap *waveform_bitmap;
77         BC_Bitmap *vector_bitmap;
79         int vector_x, vector_y, vector_w, vector_h;
80         int wave_x, wave_y, wave_w, wave_h;
83 PLUGIN_THREAD_HEADER(VideoScopeEffect, VideoScopeThread, VideoScopeWindow)
88 class VideoScopePackage : public LoadPackage
90 public:
91         VideoScopePackage();
92         int row1, row2;
96 class VideoScopeUnit : public LoadClient
98 public:
99         VideoScopeUnit(VideoScopeEffect *plugin, VideoScopeEngine *server);
100         void process_package(LoadPackage *package);
101         VideoScopeEffect *plugin;
102         YUV yuv;
105 class VideoScopeEngine : public LoadServer
107 public:
108         VideoScopeEngine(VideoScopeEffect *plugin, int cpus);
109         ~VideoScopeEngine();
110         void init_packages();
111         LoadClient* new_client();
112         LoadPackage* new_package();
113         VideoScopeEffect *plugin;
116 class VideoScopeEffect : public PluginVClient
118 public:
119         VideoScopeEffect(PluginServer *server);
120         ~VideoScopeEffect();
122         int process_realtime(VFrame *input, VFrame *output);
123         int is_realtime();
124         char* plugin_title();
125         VFrame* new_picon();
126         int load_defaults();
127         int save_defaults();
128         int show_gui();
129         int set_string();
130         void raise_window();
131         void render_gui(void *input);
132         int load_configuration();
134         int w, h;
135         VFrame *input;
136         VideoScopeConfig config;
137         VideoScopeEngine *engine;
138         Defaults *defaults;
139         VideoScopeThread *thread;
154 VideoScopeConfig::VideoScopeConfig()
167 VideoScopeWaveform::VideoScopeWaveform(VideoScopeEffect *plugin, 
168                 int x, 
169                 int y,
170                 int w,
171                 int h)
172  : BC_SubWindow(x, y, w, h, BLACK)
174         this->plugin = plugin;
178 VideoScopeVectorscope::VideoScopeVectorscope(VideoScopeEffect *plugin, 
179                 int x, 
180                 int y,
181                 int w,
182                 int h)
183  : BC_SubWindow(x, y, w, h, BLACK)
185         this->plugin = plugin;
194 VideoScopeWindow::VideoScopeWindow(VideoScopeEffect *plugin, 
195         int x, 
196         int y)
197  : BC_Window(plugin->gui_string, 
198         x, 
199         y, 
200         plugin->w, 
201         plugin->h, 
202         50, 
203         50, 
204         1, 
205         0,
206         1,
207         BLACK)
209         this->plugin = plugin;
210         waveform_bitmap = 0;
211         vector_bitmap = 0;
214 VideoScopeWindow::~VideoScopeWindow()
217         if(waveform_bitmap) delete waveform_bitmap;
218         if(vector_bitmap) delete vector_bitmap;
221 void VideoScopeWindow::calculate_sizes(int w, int h)
223         wave_x = 30;
224         wave_y = 10;
225         wave_w = w / 2 - 5 - wave_x;
226         wave_h = h - 20 - wave_y;
227         vector_x = w / 2 + 30;
228         vector_y = 10;
229         vector_w = w - 10 - vector_x;
230         vector_h = h - 10 - vector_y;
233 void VideoScopeWindow::create_objects()
235         calculate_sizes(get_w(), get_h());
237         add_subwindow(waveform = new VideoScopeWaveform(plugin, 
238                 wave_x, 
239                 wave_y, 
240                 wave_w, 
241                 wave_h));
242         add_subwindow(vectorscope = new VideoScopeVectorscope(plugin, 
243                 vector_x, 
244                 vector_y, 
245                 vector_w, 
246                 vector_h));
247         allocate_bitmaps();
248         draw_overlays();
250         show_window();
251         flush();
252         
255 WINDOW_CLOSE_EVENT(VideoScopeWindow)
257 int VideoScopeWindow::resize_event(int w, int h)
260         clear_box(0, 0, w, h);
261         plugin->w = w;
262         plugin->h = h;
263         calculate_sizes(w, h);
264         waveform->reposition_window(wave_x, wave_y, wave_w, wave_h);
265         vectorscope->reposition_window(vector_x, vector_y, vector_w, vector_h);
266         waveform->clear_box(0, 0, wave_w, wave_h);
267         vectorscope->clear_box(0, 0, wave_w, wave_h);
268         allocate_bitmaps();
269         draw_overlays();
270         flash();
272         return 1;
275 void VideoScopeWindow::allocate_bitmaps()
277         if(waveform_bitmap) delete waveform_bitmap;
278         if(vector_bitmap) delete vector_bitmap;
280         waveform_bitmap = new_bitmap(wave_w, wave_h);
281         vector_bitmap = new_bitmap(vector_w, vector_h);
284 void VideoScopeWindow::draw_overlays()
286         set_color(GREEN);
287         set_font(SMALLFONT);
289 // Waveform overlay
290         for(int i = 0; i <= WAVEFORM_DIVISIONS; i++)
291         {
292                 int y = wave_h * i / WAVEFORM_DIVISIONS;
293                 int text_y = y + wave_y + get_text_ascent(SMALLFONT) / 2;
294                 int x = wave_x - 20;
295                 char string[BCTEXTLEN];
296                 sprintf(string, "%d", 
297                         (int)((FLOAT_MAX - 
298                         i * (FLOAT_MAX - FLOAT_MIN) / WAVEFORM_DIVISIONS) * 100));
299                 draw_text(x, text_y, string);
301                 waveform->draw_line(0, 
302                         CLAMP(y, 0, waveform->get_h() - 1), 
303                         wave_w, 
304                         CLAMP(y, 0, waveform->get_h() - 1));
305 //waveform->draw_rectangle(0, 0, wave_w, wave_h);
306         }
310 // Vectorscope overlay
311         int radius = MIN(vector_w / 2, vector_h / 2);
312         for(int i = 1; i <= VECTORSCOPE_DIVISIONS - 1; i += 2)
313         {
314                 int x = vector_w / 2 - radius * i / VECTORSCOPE_DIVISIONS;
315                 int y = vector_h / 2 - radius * i / VECTORSCOPE_DIVISIONS;
316                 int text_x = vector_x - 20;
317                 int text_y = y + vector_y + get_text_ascent(SMALLFONT) / 2;
318                 int w = radius * i / VECTORSCOPE_DIVISIONS * 2;
319                 int h = radius * i / VECTORSCOPE_DIVISIONS * 2;
320                 char string[BCTEXTLEN];
321                 
322                 sprintf(string, "%d", 
323                         (int)((FLOAT_MIN + 
324                                 (FLOAT_MAX - FLOAT_MIN) / VECTORSCOPE_DIVISIONS * i) * 100));
325                 draw_text(text_x, text_y, string);
326                 vectorscope->draw_circle(x, y, w, h);
327 //vectorscope->draw_rectangle(0, 0, vector_w, vector_h);
328         }
329 //      vectorscope->draw_circle(vector_w / 2 - radius, 
330 //              vector_h / 2 - radius, 
331 //              radius * 2, 
332 //              radius * 2);
333         set_font(MEDIUMFONT);
335         waveform->flash();
336         vectorscope->flash();
337         flush();
347 PLUGIN_THREAD_OBJECT(VideoScopeEffect, VideoScopeThread, VideoScopeWindow)
353 REGISTER_PLUGIN(VideoScopeEffect)
360 VideoScopeEffect::VideoScopeEffect(PluginServer *server)
361  : PluginVClient(server)
363         engine = 0;
364         w = 640;
365         h = 260;
366         PLUGIN_CONSTRUCTOR_MACRO
369 VideoScopeEffect::~VideoScopeEffect()
371         PLUGIN_DESTRUCTOR_MACRO
373         if(engine) delete engine;
378 char* VideoScopeEffect::plugin_title() { return N_("VideoScope"); }
379 int VideoScopeEffect::is_realtime() { return 1; }
381 int VideoScopeEffect::load_configuration()
383         return 0;
386 NEW_PICON_MACRO(VideoScopeEffect)
388 SHOW_GUI_MACRO(VideoScopeEffect, VideoScopeThread)
390 RAISE_WINDOW_MACRO(VideoScopeEffect)
392 SET_STRING_MACRO(VideoScopeEffect)
394 int VideoScopeEffect::load_defaults()
396         char directory[BCTEXTLEN];
397 // set the default directory
398         sprintf(directory, "%svideoscope.rc", BCASTDIR);
400 // load the defaults
401         defaults = new Defaults(directory);
402         defaults->load();
404         w = defaults->get("W", w);
405         h = defaults->get("H", h);
406         return 0;
409 int VideoScopeEffect::save_defaults()
411         defaults->update("W", w);
412         defaults->update("H", h);
413         defaults->save();
414         return 0;
417 int VideoScopeEffect::process_realtime(VFrame *input, VFrame *output)
420         send_render_gui(input);
421 //printf("VideoScopeEffect::process_realtime 1\n");
422         if(input->get_rows()[0] != output->get_rows()[0])
423                 output->copy_from(input);
424         return 1;
427 void VideoScopeEffect::render_gui(void *input)
429         if(thread)
430         {
431                 VideoScopeWindow *window = thread->window;
432                 window->lock_window();
434 //printf("VideoScopeEffect::process_realtime 1\n");
435                 this->input = (VFrame*)input;
436 //printf("VideoScopeEffect::process_realtime 1\n");
439                 if(!engine)
440                 {
441                         engine = new VideoScopeEngine(this, 
442                                 (PluginClient::smp + 1));
443                 }
445 //printf("VideoScopeEffect::process_realtime 1 %d\n", PluginClient::smp);
446 // Clear bitmaps
447                 bzero(window->waveform_bitmap->get_data(), 
448                         window->waveform_bitmap->get_h() * 
449                         window->waveform_bitmap->get_bytes_per_line());
450                 bzero(window->vector_bitmap->get_data(), 
451                         window->vector_bitmap->get_h() * 
452                         window->vector_bitmap->get_bytes_per_line());
454                 engine->process_packages();
455 //printf("VideoScopeEffect::process_realtime 2\n");
456 //printf("VideoScopeEffect::process_realtime 1\n");
458                 window->waveform->draw_bitmap(window->waveform_bitmap, 
459                         1,
460                         0,
461                         0);
463 //printf("VideoScopeEffect::process_realtime 1\n");
464                 window->vectorscope->draw_bitmap(window->vector_bitmap, 
465                         1,
466                         0,
467                         0);
470                 window->draw_overlays();
473                 window->unlock_window();
474         }
481 VideoScopePackage::VideoScopePackage()
482  : LoadPackage()
491 VideoScopeUnit::VideoScopeUnit(VideoScopeEffect *plugin, 
492         VideoScopeEngine *server)
493  : LoadClient(server)
495         this->plugin = plugin;
499 #define INTENSITY(p) ((unsigned int)(((p)[0]) * 77+ \
500                                                                         ((p)[1] * 150) + \
501                                                                         ((p)[2] * 29)) >> 8)
504 static void draw_point(unsigned char **rows, 
505         int color_model, 
506         int x, 
507         int y, 
508         int r, 
509         int g, 
510         int b)
512         switch(color_model)
513         {
514                 case BC_BGR8888:
515                 {
516                         unsigned char *pixel = rows[y] + x * 4;
517                         pixel[0] = r;
518                         pixel[1] = g;
519                         pixel[2] = b;
520                         break;
521                 }
522                 case BC_BGR888:
523                         break;
524                 case BC_RGB565:
525                 {
526                         unsigned char *pixel = rows[y] + x * 2;
527                         pixel[0] = (r & 0xf8) | (g >> 5);
528                         pixel[1] = ((g & 0xfc) << 5) | (b >> 3);
529                         break;
530                 }
531                 case BC_BGR565:
532                         break;
533                 case BC_RGB8:
534                         break;
535         }
540 #define VIDEOSCOPE(type, temp_type, max, components, use_yuv) \
541 { \
542         for(int i = pkg->row1; i < pkg->row2; i++) \
543         { \
544                 type *in_row = (type*)plugin->input->get_rows()[i]; \
545                 for(int j = 0; j < w; j++) \
546                 { \
547                         type *in_pixel = in_row + j * components; \
548                         float intensity; \
550 /* Analyze pixel */ \
551                         if(use_yuv) intensity = (float)*in_pixel / max; \
553                         float h, s, v; \
554                         temp_type r, g, b; \
555                         if(use_yuv) \
556                         { \
557                                 if(sizeof(type) == 2) \
558                                 { \
559                                         yuv.yuv_to_rgb_16(r, \
560                                                 g, \
561                                                 b, \
562                                                 in_pixel[0], \
563                                                 in_pixel[1], \
564                                                 in_pixel[2]); \
565                                 } \
566                                 else \
567                                 { \
568                                         yuv.yuv_to_rgb_8(r, \
569                                                 g, \
570                                                 b, \
571                                                 in_pixel[0], \
572                                                 in_pixel[1], \
573                                                 in_pixel[2]); \
574                                 } \
575                         } \
576                         else \
577                         { \
578                                 r = in_pixel[0]; \
579                                 g = in_pixel[1]; \
580                                 b = in_pixel[2]; \
581                         } \
583                         HSV::rgb_to_hsv((float)r / max, \
584                                         (float)g / max, \
585                                         (float)b / max, \
586                                         h, \
587                                         s, \
588                                         v); \
590 /* Calculate waveform */ \
591                         if(!use_yuv) intensity = v; \
592                         intensity = (intensity - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN) * \
593                                 waveform_h; \
594                         int y = waveform_h - (int)intensity; \
595                         int x = j * waveform_w / w; \
596                         if(x >= 0 && x < waveform_w && y >= 0 && y < waveform_h) \
597                                 draw_point(waveform_rows, \
598                                         waveform_cmodel, \
599                                         x, \
600                                         y, \
601                                         0xff, \
602                                         0xff, \
603                                         0xff); \
605 /* Calculate vectorscope */ \
606                         float adjacent = cos(h / 360 * 2 * M_PI); \
607                         float opposite = sin(h / 360 * 2 * M_PI); \
608                         x = (int)(vector_w / 2 +  \
609                                 adjacent * (s - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN) * radius); \
611                         y = (int)(vector_h / 2 -  \
612                                 opposite * (s - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN) * radius); \
615                         CLAMP(x, 0, vector_w - 1); \
616                         CLAMP(y, 0, vector_h - 1); \
617                         if(sizeof(type) == 2) \
618                         { \
619                                 r /= 256; \
620                                 g /= 256; \
621                                 b /= 256; \
622                         } \
623                         else \
624                         if(sizeof(type) == 4) \
625                         { \
626                                 r = CLIP(r, 0, 1) * 0xff; \
627                                 g = CLIP(g, 0, 1) * 0xff; \
628                                 b = CLIP(b, 0, 1) * 0xff; \
629                         } \
631                         draw_point(vector_rows, \
632                                 vector_cmodel, \
633                                 x, \
634                                 y, \
635                                 (int)r, \
636                                 (int)g, \
637                                 (int)b); \
639                 } \
640         } \
643 void VideoScopeUnit::process_package(LoadPackage *package)
645         VideoScopeWindow *window = plugin->thread->window;
646         VideoScopePackage *pkg = (VideoScopePackage*)package;
647         int w = plugin->input->get_w();
648         int h = plugin->input->get_h();
649         int waveform_h = window->wave_h;
650         int waveform_w = window->wave_w;
651         int waveform_cmodel = window->waveform_bitmap->get_color_model();
652         unsigned char **waveform_rows = window->waveform_bitmap->get_row_pointers();
653         int vector_h = window->vector_bitmap->get_h();
654         int vector_w = window->vector_bitmap->get_w();
655         int vector_cmodel = window->vector_bitmap->get_color_model();
656         unsigned char **vector_rows = window->vector_bitmap->get_row_pointers();
657         float radius = MIN(vector_w / 2, vector_h / 2);
659         switch(plugin->input->get_color_model())
660         {
661                 case BC_RGB888:
662                         VIDEOSCOPE(unsigned char, int, 0xff, 3, 0)
663                         break;
665                 case BC_RGB_FLOAT:
666                         VIDEOSCOPE(float, float, 1, 3, 0)
667                         break;
669                 case BC_YUV888:
670                         VIDEOSCOPE(unsigned char, int, 0xff, 3, 1)
671                         break;
673                 case BC_RGB161616:
674                         VIDEOSCOPE(uint16_t, int, 0xffff, 3, 0)
675                         break;
677                 case BC_YUV161616:
678                         VIDEOSCOPE(uint16_t, int, 0xffff, 3, 1)
679                         break;
681                 case BC_RGBA8888:
682                         VIDEOSCOPE(unsigned char, int, 0xff, 4, 0)
683                         break;
685                 case BC_RGBA_FLOAT:
686                         VIDEOSCOPE(float, float, 1, 4, 0)
687                         break;
689                 case BC_YUVA8888:
690                         VIDEOSCOPE(unsigned char, int, 0xff, 4, 1)
691                         break;
693                 case BC_RGBA16161616:
694                         VIDEOSCOPE(uint16_t, int, 0xffff, 4, 0)
695                         break;
697                 case BC_YUVA16161616:
698                         VIDEOSCOPE(uint16_t, int, 0xffff, 4, 1)
699                         break;
700         }
708 VideoScopeEngine::VideoScopeEngine(VideoScopeEffect *plugin, int cpus)
709  : LoadServer(cpus, cpus)
711         this->plugin = plugin;
714 VideoScopeEngine::~VideoScopeEngine()
718 void VideoScopeEngine::init_packages()
720         int increment = plugin->input->get_h() / LoadServer::total_packages + 1;
721         int y = 0;
722         for(int i = 0; i < LoadServer::total_packages; i++)
723         {
724                 VideoScopePackage *pkg = (VideoScopePackage*)packages[i];
725                 pkg->row1 = y;
726                 pkg->row2 = y + increment;
727                 y += increment;
728                 if(pkg->row2 > plugin->input->get_h())
729                 {
730                         y = pkg->row2 = plugin->input->get_h();
731                 }
732         }
736 LoadClient* VideoScopeEngine::new_client()
738         return new VideoScopeUnit(plugin, this);
741 LoadPackage* VideoScopeEngine::new_package()
743         return new VideoScopePackage;