update internationalization data
[goodguy/history.git] / cinelerra-5.0 / plugins / videoscope / videoscope.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
5  * 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  * 
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "clip.h"
24 #include "bchash.h"
25 #include "filexml.h"
26 #include "guicast.h"
27 #include "language.h"
28 #include "loadbalance.h"
29 #include "cicolors.h"
30 #include "pluginvclient.h"
31 #include "fonts.h"
32 #include "scopewindow.h"
33 #include "theme.h"
34 #include "vframe.h"
35
36 #include <math.h>
37 #include <stdint.h>
38 #include <string.h>
39
40
41
42
43
44 class VideoScopeEffect;
45 class VideoScopeEngine;
46 class VideoScopeWindow;
47
48 class VideoScopeConfig
49 {
50 public:
51         VideoScopeConfig();
52 };
53
54 class VideoScopeWindow : public ScopeGUI
55 {
56 public:
57         VideoScopeWindow(VideoScopeEffect *plugin);
58         ~VideoScopeWindow();
59
60         void create_objects();
61         void toggle_event();
62         int resize_event(int w, int h);
63         void update();
64
65         VideoScopeEffect *plugin;
66 };
67
68
69
70
71
72 class VideoScopePackage : public LoadPackage
73 {
74 public:
75         VideoScopePackage();
76         int row1, row2;
77 };
78
79
80 class VideoScopeUnit : public LoadClient
81 {
82 public:
83         VideoScopeUnit(VideoScopeEffect *plugin, VideoScopeEngine *server);
84         void process_package(LoadPackage *package);
85         VideoScopeEffect *plugin;
86         YUV yuv;
87 };
88
89 class VideoScopeEngine : public LoadServer
90 {
91 public:
92         VideoScopeEngine(VideoScopeEffect *plugin, int cpus);
93         ~VideoScopeEngine();
94         void init_packages();
95         LoadClient* new_client();
96         LoadPackage* new_package();
97         VideoScopeEffect *plugin;
98 };
99
100 class VideoScopeEffect : public PluginVClient
101 {
102 public:
103         VideoScopeEffect(PluginServer *server);
104         ~VideoScopeEffect();
105
106
107         PLUGIN_CLASS_MEMBERS2(VideoScopeConfig)
108         int process_realtime(VFrame *input, VFrame *output);
109         int is_realtime();
110         void render_gui(void *input);
111         void save_data(KeyFrame *keyframe);
112         void read_data(KeyFrame *keyframe);
113
114         int use_hist, use_wave, use_vector;
115         int use_hist_parade, use_wave_parade;
116         int w, h;
117         VFrame *input;
118 };
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133 VideoScopeConfig::VideoScopeConfig()
134 {
135 }
136
137
138
139
140
141
142
143
144
145
146
147
148 VideoScopeWindow::VideoScopeWindow(VideoScopeEffect *plugin)
149  : ScopeGUI(plugin, 
150         plugin->w, 
151         plugin->h)
152 {
153         this->plugin = plugin;
154 }
155
156 VideoScopeWindow::~VideoScopeWindow()
157 {
158 }
159
160 void VideoScopeWindow::create_objects()
161 {
162         use_hist = plugin->use_hist;
163         use_wave = plugin->use_wave;
164         use_vector = plugin->use_vector;
165         use_hist_parade = plugin->use_hist_parade;
166         use_wave_parade = plugin->use_wave_parade;
167         ScopeGUI::create_objects();
168 }
169
170 void VideoScopeWindow::toggle_event()
171 {
172         plugin->use_hist = use_hist;
173         plugin->use_wave = use_wave;
174         plugin->use_vector = use_vector;
175         plugin->use_hist_parade = use_hist_parade;
176         plugin->use_wave_parade = use_wave_parade;
177 // Make it reprocess
178         plugin->send_configure_change();
179 }
180
181
182 int VideoScopeWindow::resize_event(int w, int h)
183 {
184         ScopeGUI::resize_event(w, h);
185         plugin->w = w;
186         plugin->h = h;
187 // Make it reprocess
188         plugin->send_configure_change();
189         return 1;
190 }
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211 REGISTER_PLUGIN(VideoScopeEffect)
212
213
214
215
216
217
218 VideoScopeEffect::VideoScopeEffect(PluginServer *server)
219  : PluginVClient(server)
220 {
221         w = MIN_SCOPE_W;
222         h = MIN_SCOPE_H;
223         use_hist = 0;
224         use_wave = 0;
225         use_vector = 1;
226         use_hist_parade = 1;
227         use_wave_parade = 1;
228 }
229
230 VideoScopeEffect::~VideoScopeEffect()
231 {
232         
233
234 }
235
236
237
238 const char* VideoScopeEffect::plugin_title() { return _("VideoScope"); }
239 int VideoScopeEffect::is_realtime() { return 1; }
240
241 int VideoScopeEffect::load_configuration()
242 {
243         return 0;
244 }
245
246 void VideoScopeEffect::save_data(KeyFrame *keyframe)
247 {
248         FileXML output;
249
250 // cause data to be stored directly in text
251         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
252         output.tag.set_title("VIDEOSCOPE");
253
254
255         if(is_defaults())
256         {
257                 output.tag.set_property("W", w);
258                 output.tag.set_property("H", h);
259                 output.tag.set_property("USE_HIST", use_hist);
260                 output.tag.set_property("USE_WAVE", use_wave);
261                 output.tag.set_property("USE_VECTOR", use_vector);
262                 output.tag.set_property("USE_HIST_PARADE", use_hist_parade);
263                 output.tag.set_property("USE_WAVE_PARADE", use_wave_parade);
264         }
265
266         output.append_tag();
267         output.append_newline();
268         output.terminate_string();
269 }
270
271 void VideoScopeEffect::read_data(KeyFrame *keyframe)
272 {
273         FileXML input;
274         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
275
276         int result = 0;
277
278
279         while(!result)
280         {
281                 result = input.read_tag();
282
283                 if(!result)
284                 {
285                         if(input.tag.title_is("VIDEOSCOPE"))
286                         {
287                                 if(is_defaults())
288                                 {
289                                         w = input.tag.get_property("W", w);
290                                         h = input.tag.get_property("H", h);
291                                         use_hist = input.tag.get_property("USE_HIST", use_hist);
292                                         use_wave = input.tag.get_property("USE_WAVE", use_wave);
293                                         use_vector = input.tag.get_property("USE_VECTOR", use_vector);
294                                         use_hist_parade = input.tag.get_property("USE_HIST_PARADE", use_hist_parade);
295                                         use_wave_parade = input.tag.get_property("USE_WAVE_PARADE", use_wave_parade);
296                                 }
297                         }
298                 }
299         }
300 }
301
302
303
304
305 NEW_WINDOW_MACRO(VideoScopeEffect, VideoScopeWindow)
306
307
308 int VideoScopeEffect::process_realtime(VFrame *input, VFrame *output)
309 {
310
311         send_render_gui(input);
312 //printf("VideoScopeEffect::process_realtime 1\n");
313         if(input->get_rows()[0] != output->get_rows()[0])
314                 output->copy_from(input);
315         return 1;
316 }
317
318 void VideoScopeEffect::render_gui(void *input)
319 {
320         if(thread)
321         {
322                 VideoScopeWindow *window = ((VideoScopeWindow*)thread->window);
323                 window->lock_window();
324
325 //printf("VideoScopeEffect::process_realtime 1\n");
326                 this->input = (VFrame*)input;
327 //printf("VideoScopeEffect::process_realtime 1\n");
328                 window->process(this->input);
329
330
331                 window->unlock_window();
332         }
333 }
334
335
336
337
338
339 VideoScopePackage::VideoScopePackage()
340  : LoadPackage()
341 {
342 }
343
344
345
346
347
348
349 VideoScopeUnit::VideoScopeUnit(VideoScopeEffect *plugin, 
350         VideoScopeEngine *server)
351  : LoadClient(server)
352 {
353         this->plugin = plugin;
354 }
355
356
357 #define INTENSITY(p) ((unsigned int)(((p)[0]) * 77+ \
358                                                                         ((p)[1] * 150) + \
359                                                                         ((p)[2] * 29)) >> 8)
360
361
362 static void draw_point(unsigned char **rows, 
363         int color_model, 
364         int x, 
365         int y, 
366         int r, 
367         int g, 
368         int b)
369 {
370         switch(color_model)
371         {
372                 case BC_BGR8888:
373                 {
374                         unsigned char *pixel = rows[y] + x * 4;
375                         pixel[0] = b;
376                         pixel[1] = g;
377                         pixel[2] = r;
378                         break;
379                 }
380                 case BC_BGR888:
381                         break;
382                 case BC_RGB565:
383                 {
384                         unsigned char *pixel = rows[y] + x * 2;
385                         pixel[0] = (r & 0xf8) | (g >> 5);
386                         pixel[1] = ((g & 0xfc) << 5) | (b >> 3);
387                         break;
388                 }
389                 case BC_BGR565:
390                         break;
391                 case BC_RGB8:
392                         break;
393         }
394 }
395
396
397
398 #define VIDEOSCOPE(type, temp_type, max, components, use_yuv) \
399 { \
400         for(int i = pkg->row1; i < pkg->row2; i++) \
401         { \
402                 type *in_row = (type*)plugin->input->get_rows()[i]; \
403                 for(int j = 0; j < w; j++) \
404                 { \
405                         type *in_pixel = in_row + j * components; \
406                         float intensity; \
407  \
408 /* Analyze pixel */ \
409                         if(use_yuv) intensity = (float)*in_pixel / max; \
410  \
411                         float h, s, v; \
412                         temp_type r, g, b; \
413                         if(use_yuv) \
414                         { \
415                                 if(sizeof(type) == 2) \
416                                 { \
417                                         yuv.yuv_to_rgb_16(r, \
418                                                 g, \
419                                                 b, \
420                                                 in_pixel[0], \
421                                                 in_pixel[1], \
422                                                 in_pixel[2]); \
423                                 } \
424                                 else \
425                                 { \
426                                         yuv.yuv_to_rgb_8(r, \
427                                                 g, \
428                                                 b, \
429                                                 in_pixel[0], \
430                                                 in_pixel[1], \
431                                                 in_pixel[2]); \
432                                 } \
433                         } \
434                         else \
435                         { \
436                                 r = in_pixel[0]; \
437                                 g = in_pixel[1]; \
438                                 b = in_pixel[2]; \
439                         } \
440  \
441                         HSV::rgb_to_hsv((float)r / max, \
442                                         (float)g / max, \
443                                         (float)b / max, \
444                                         h, \
445                                         s, \
446                                         v); \
447  \
448 /* Calculate waveform */ \
449                         if(parade) \
450                         { \
451 /* red */ \
452                                 int x = j * waveform_w / w / 3; \
453                                 int y = waveform_h - (int)(((float)r / max - FLOAT_MIN) / \
454                                         (FLOAT_MAX - FLOAT_MIN) * \
455                                         waveform_h); \
456                                 if(x >= 0 && x < waveform_w / 3 && y >= 0 && y < waveform_h) \
457                                         draw_point(waveform_rows, \
458                                                 waveform_cmodel, \
459                                                 x, \
460                                                 y, \
461                                                 0xff, \
462                                                 0x0, \
463                                                 0x0); \
464  \
465 /* green */ \
466                                 x = waveform_w / 3 + j * waveform_w / w / 3; \
467                                 y = waveform_h - (int)(((float)g / max - FLOAT_MIN) / \
468                                         (FLOAT_MAX - FLOAT_MIN) * \
469                                         waveform_h); \
470                                 if(x >= waveform_w / 3 && x < waveform_w * 2 / 3 && \
471                                         y >= 0 && y < waveform_h) \
472                                         draw_point(waveform_rows, \
473                                                 waveform_cmodel, \
474                                                 x, \
475                                                 y, \
476                                                 0x0, \
477                                                 0xff, \
478                                                 0x0); \
479  \
480 /* blue */ \
481                                 x = waveform_w * 2 / 3 + j * waveform_w / w / 3; \
482                                 y = waveform_h - (int)(((float)b / max - FLOAT_MIN) / \
483                                         (FLOAT_MAX - FLOAT_MIN) * \
484                                         waveform_h); \
485                                 if(x >= waveform_w * 2 / 3 && x < waveform_w && \
486                                         y >= 0 && y < waveform_h) \
487                                         draw_point(waveform_rows, \
488                                                 waveform_cmodel, \
489                                                 x, \
490                                                 y, \
491                                                 0x0, \
492                                                 0x0, \
493                                                 0xff); \
494                         } \
495                         else \
496                         { \
497                                 if(!use_yuv) intensity = v; \
498                                 intensity = (intensity - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN) * \
499                                         waveform_h; \
500                                 int y = waveform_h - (int)intensity; \
501                                 int x = j * waveform_w / w; \
502                                 if(x >= 0 && x < waveform_w && y >= 0 && y < waveform_h) \
503                                         draw_point(waveform_rows, \
504                                                 waveform_cmodel, \
505                                                 x, \
506                                                 y, \
507                                                 0xff, \
508                                                 0xff, \
509                                                 0xff); \
510                         } \
511  \
512 /* Calculate vectorscope */ \
513                         float adjacent = cos((h + 90) / 360 * 2 * M_PI); \
514                         float opposite = sin((h + 90) / 360 * 2 * M_PI); \
515                         int x = (int)(vector_w / 2 +  \
516                                 adjacent * (s - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN) * radius); \
517  \
518                         int y = (int)(vector_h / 2 -  \
519                                 opposite * (s - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN) * radius); \
520  \
521  \
522                         CLAMP(x, 0, vector_w - 1); \
523                         CLAMP(y, 0, vector_h - 1); \
524 /* Get color with full saturation & value */ \
525                         float r_f, g_f, b_f; \
526                         HSV::hsv_to_rgb(r_f, \
527                                         g_f, \
528                                         b_f, \
529                                         h, \
530                                         s, \
531                                         1); \
532                         r = (int)(r_f * 255); \
533                         g = (int)(g_f * 255); \
534                         b = (int)(b_f * 255); \
535  \
536  /* float */ \
537                         if(sizeof(type) == 4) \
538                         { \
539                                 r = CLIP(r, 0, 0xff); \
540                                 g = CLIP(g, 0, 0xff); \
541                                 b = CLIP(b, 0, 0xff); \
542                         } \
543  \
544                         draw_point(vector_rows, \
545                                 vector_cmodel, \
546                                 x, \
547                                 y, \
548                                 (int)r, \
549                                 (int)g, \
550                                 (int)b); \
551  \
552                 } \
553         } \
554 }
555
556 void VideoScopeUnit::process_package(LoadPackage *package)
557 {
558         VideoScopeWindow *window = (VideoScopeWindow*)plugin->thread->window;
559         VideoScopePackage *pkg = (VideoScopePackage*)package;
560         int w = plugin->input->get_w();
561 //      int h = plugin->input->get_h();
562         int waveform_h = window->wave_h;
563         int waveform_w = window->wave_w;
564         int waveform_cmodel = window->waveform_bitmap->get_color_model();
565         unsigned char **waveform_rows = window->waveform_bitmap->get_row_pointers();
566         int vector_h = window->vector_bitmap->get_h();
567         int vector_w = window->vector_bitmap->get_w();
568         int vector_cmodel = window->vector_bitmap->get_color_model();
569         unsigned char **vector_rows = window->vector_bitmap->get_row_pointers();
570         float radius = MIN(vector_w / 2, vector_h / 2);
571         int parade = 1;
572
573         switch(plugin->input->get_color_model())
574         {
575                 case BC_RGB888:
576                         VIDEOSCOPE(unsigned char, int, 0xff, 3, 0)
577                         break;
578
579                 case BC_RGB_FLOAT:
580                         VIDEOSCOPE(float, float, 1, 3, 0)
581                         break;
582
583                 case BC_YUV888:
584                         VIDEOSCOPE(unsigned char, int, 0xff, 3, 1)
585                         break;
586
587                 case BC_RGB161616:
588                         VIDEOSCOPE(uint16_t, int, 0xffff, 3, 0)
589                         break;
590
591                 case BC_YUV161616:
592                         VIDEOSCOPE(uint16_t, int, 0xffff, 3, 1)
593                         break;
594
595                 case BC_RGBA8888:
596                         VIDEOSCOPE(unsigned char, int, 0xff, 4, 0)
597                         break;
598
599                 case BC_RGBA_FLOAT:
600                         VIDEOSCOPE(float, float, 1, 4, 0)
601                         break;
602
603                 case BC_YUVA8888:
604                         VIDEOSCOPE(unsigned char, int, 0xff, 4, 1)
605                         break;
606
607                 case BC_RGBA16161616:
608                         VIDEOSCOPE(uint16_t, int, 0xffff, 4, 0)
609                         break;
610
611                 case BC_YUVA16161616:
612                         VIDEOSCOPE(uint16_t, int, 0xffff, 4, 1)
613                         break;
614         }
615 }
616
617
618
619
620
621
622 VideoScopeEngine::VideoScopeEngine(VideoScopeEffect *plugin, int cpus)
623  : LoadServer(cpus, cpus)
624 {
625         this->plugin = plugin;
626 }
627
628 VideoScopeEngine::~VideoScopeEngine()
629 {
630 }
631
632 void VideoScopeEngine::init_packages()
633 {
634         for(int i = 0; i < LoadServer::get_total_packages(); i++)
635         {
636                 VideoScopePackage *pkg = (VideoScopePackage*)get_package(i);
637                 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
638                 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
639         }
640 }
641
642
643 LoadClient* VideoScopeEngine::new_client()
644 {
645         return new VideoScopeUnit(plugin, this);
646 }
647
648 LoadPackage* VideoScopeEngine::new_package()
649 {
650         return new VideoScopePackage;
651 }
652