577224326d6a5cd2781d7ac1e95058faab0ef9e9
[goodguy/history.git] / cinelerra-5.1 / 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 "bccolors.h"
24 #include "clip.h"
25 #include "bchash.h"
26 #include "filexml.h"
27 #include "guicast.h"
28 #include "language.h"
29 #include "loadbalance.h"
30 #include "bccolors.h"
31 #include "pluginvclient.h"
32 #include "fonts.h"
33 #include "scopewindow.h"
34 #include "theme.h"
35 #include "vframe.h"
36
37 #include <math.h>
38 #include <stdint.h>
39 #include <string.h>
40
41
42
43
44
45 class VideoScopeEffect;
46 class VideoScopeEngine;
47 class VideoScopeWindow;
48
49 class VideoScopeConfig
50 {
51 public:
52         VideoScopeConfig();
53 };
54
55 class VideoScopeWindow : public ScopeGUI
56 {
57 public:
58         VideoScopeWindow(VideoScopeEffect *plugin);
59         ~VideoScopeWindow();
60
61         void create_objects();
62         void toggle_event();
63         int resize_event(int w, int h);
64         void update();
65
66         VideoScopeEffect *plugin;
67 };
68
69
70
71
72
73 class VideoScopePackage : public LoadPackage
74 {
75 public:
76         VideoScopePackage();
77         int row1, row2;
78 };
79
80
81 class VideoScopeUnit : public LoadClient
82 {
83 public:
84         VideoScopeUnit(VideoScopeEffect *plugin, VideoScopeEngine *server);
85         void process_package(LoadPackage *package);
86         VideoScopeEffect *plugin;
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.tag.set_title("/VIDEOSCOPE");
268         output.append_tag();
269         output.append_newline();
270         output.terminate_string();
271 }
272
273 void VideoScopeEffect::read_data(KeyFrame *keyframe)
274 {
275         FileXML input;
276         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
277
278         int result = 0;
279
280
281         while(!result)
282         {
283                 result = input.read_tag();
284
285                 if(!result)
286                 {
287                         if(input.tag.title_is("VIDEOSCOPE"))
288                         {
289                                 if(is_defaults())
290                                 {
291                                         w = input.tag.get_property("W", w);
292                                         h = input.tag.get_property("H", h);
293                                         use_hist = input.tag.get_property("USE_HIST", use_hist);
294                                         use_wave = input.tag.get_property("USE_WAVE", use_wave);
295                                         use_vector = input.tag.get_property("USE_VECTOR", use_vector);
296                                         use_hist_parade = input.tag.get_property("USE_HIST_PARADE", use_hist_parade);
297                                         use_wave_parade = input.tag.get_property("USE_WAVE_PARADE", use_wave_parade);
298                                 }
299                         }
300                 }
301         }
302 }
303
304
305
306
307 NEW_WINDOW_MACRO(VideoScopeEffect, VideoScopeWindow)
308
309
310 int VideoScopeEffect::process_realtime(VFrame *input, VFrame *output)
311 {
312
313         send_render_gui(input);
314 //printf("VideoScopeEffect::process_realtime 1\n");
315         if(input->get_rows()[0] != output->get_rows()[0])
316                 output->copy_from(input);
317         return 1;
318 }
319
320 void VideoScopeEffect::render_gui(void *input)
321 {
322         if(thread)
323         {
324                 VideoScopeWindow *window = ((VideoScopeWindow*)thread->window);
325                 window->lock_window();
326
327 //printf("VideoScopeEffect::process_realtime 1\n");
328                 this->input = (VFrame*)input;
329 //printf("VideoScopeEffect::process_realtime 1\n");
330                 window->process(this->input);
331
332
333                 window->unlock_window();
334         }
335 }
336
337
338
339
340
341 VideoScopePackage::VideoScopePackage()
342  : LoadPackage()
343 {
344 }
345
346
347
348
349
350
351 VideoScopeUnit::VideoScopeUnit(VideoScopeEffect *plugin,
352         VideoScopeEngine *server)
353  : LoadClient(server)
354 {
355         this->plugin = plugin;
356 }
357
358
359 #define INTENSITY(p) ((unsigned int)(((p)[0]) * 77+ \
360                                                                         ((p)[1] * 150) + \
361                                                                         ((p)[2] * 29)) >> 8)
362
363
364 static void draw_point(unsigned char **rows,
365         int color_model,
366         int x,
367         int y,
368         int r,
369         int g,
370         int b)
371 {
372         switch(color_model)
373         {
374                 case BC_BGR8888:
375                 {
376                         unsigned char *pixel = rows[y] + x * 4;
377                         pixel[0] = b;
378                         pixel[1] = g;
379                         pixel[2] = r;
380                         break;
381                 }
382                 case BC_BGR888:
383                         break;
384                 case BC_RGB565:
385                 {
386                         unsigned char *pixel = rows[y] + x * 2;
387                         pixel[0] = (r & 0xf8) | (g >> 5);
388                         pixel[1] = ((g & 0xfc) << 5) | (b >> 3);
389                         break;
390                 }
391                 case BC_BGR565:
392                         break;
393                 case BC_RGB8:
394                         break;
395         }
396 }
397
398
399
400 #define VIDEOSCOPE(type, temp_type, max, components, use_yuv) \
401 { \
402         for(int i = pkg->row1; i < pkg->row2; i++) \
403         { \
404                 type *in_row = (type*)plugin->input->get_rows()[i]; \
405                 for(int j = 0; j < w; j++) \
406                 { \
407                         type *in_pixel = in_row + j * components; \
408                         float intensity; \
409  \
410 /* Analyze pixel */ \
411                         if(use_yuv) intensity = (float)*in_pixel / max; \
412  \
413                         float h, s, v; \
414                         temp_type r, g, b; \
415                         if(use_yuv) \
416                         { \
417                                 if(sizeof(type) == 2) \
418                                 { \
419                                         YUV::yuv.yuv_to_rgb_16(r, g, b, \
420                                                 in_pixel[0], in_pixel[1], in_pixel[2]); \
421                                 } \
422                                 else \
423                                 { \
424                                         YUV::yuv.yuv_to_rgb_8(r, g, b, \
425                                                 in_pixel[0], in_pixel[1], in_pixel[2]); \
426                                 } \
427                         } \
428                         else \
429                         { \
430                                 r = in_pixel[0]; \
431                                 g = in_pixel[1]; \
432                                 b = in_pixel[2]; \
433                         } \
434  \
435                         HSV::rgb_to_hsv((float)r / max, \
436                                         (float)g / max, \
437                                         (float)b / max, \
438                                         h, \
439                                         s, \
440                                         v); \
441  \
442 /* Calculate waveform */ \
443                         if(parade) \
444                         { \
445 /* red */ \
446                                 int x = j * waveform_w / w / 3; \
447                                 int y = waveform_h - (int)(((float)r / max - FLOAT_MIN) / \
448                                         (FLOAT_MAX - FLOAT_MIN) * \
449                                         waveform_h); \
450                                 if(x >= 0 && x < waveform_w / 3 && y >= 0 && y < waveform_h) \
451                                         draw_point(waveform_rows, \
452                                                 waveform_cmodel, \
453                                                 x, \
454                                                 y, \
455                                                 0xff, \
456                                                 0x0, \
457                                                 0x0); \
458  \
459 /* green */ \
460                                 x = waveform_w / 3 + j * waveform_w / w / 3; \
461                                 y = waveform_h - (int)(((float)g / max - FLOAT_MIN) / \
462                                         (FLOAT_MAX - FLOAT_MIN) * \
463                                         waveform_h); \
464                                 if(x >= waveform_w / 3 && x < waveform_w * 2 / 3 && \
465                                         y >= 0 && y < waveform_h) \
466                                         draw_point(waveform_rows, \
467                                                 waveform_cmodel, \
468                                                 x, \
469                                                 y, \
470                                                 0x0, \
471                                                 0xff, \
472                                                 0x0); \
473  \
474 /* blue */ \
475                                 x = waveform_w * 2 / 3 + j * waveform_w / w / 3; \
476                                 y = waveform_h - (int)(((float)b / max - FLOAT_MIN) / \
477                                         (FLOAT_MAX - FLOAT_MIN) * \
478                                         waveform_h); \
479                                 if(x >= waveform_w * 2 / 3 && x < waveform_w && \
480                                         y >= 0 && y < waveform_h) \
481                                         draw_point(waveform_rows, \
482                                                 waveform_cmodel, \
483                                                 x, \
484                                                 y, \
485                                                 0x0, \
486                                                 0x0, \
487                                                 0xff); \
488                         } \
489                         else \
490                         { \
491                                 if(!use_yuv) intensity = v; \
492                                 intensity = (intensity - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN) * \
493                                         waveform_h; \
494                                 int y = waveform_h - (int)intensity; \
495                                 int x = j * waveform_w / w; \
496                                 if(x >= 0 && x < waveform_w && y >= 0 && y < waveform_h) \
497                                         draw_point(waveform_rows, \
498                                                 waveform_cmodel, \
499                                                 x, \
500                                                 y, \
501                                                 0xff, \
502                                                 0xff, \
503                                                 0xff); \
504                         } \
505  \
506 /* Calculate vectorscope */ \
507                         float adjacent = cos((h + 90) / 360 * 2 * M_PI); \
508                         float opposite = sin((h + 90) / 360 * 2 * M_PI); \
509                         int x = (int)(vector_w / 2 +  \
510                                 adjacent * (s - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN) * radius); \
511  \
512                         int y = (int)(vector_h / 2 -  \
513                                 opposite * (s - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN) * radius); \
514  \
515  \
516                         CLAMP(x, 0, vector_w - 1); \
517                         CLAMP(y, 0, vector_h - 1); \
518 /* Get color with full saturation & value */ \
519                         float r_f, g_f, b_f; \
520                         HSV::hsv_to_rgb(r_f, \
521                                         g_f, \
522                                         b_f, \
523                                         h, \
524                                         s, \
525                                         1); \
526                         r = (int)(r_f * 255); \
527                         g = (int)(g_f * 255); \
528                         b = (int)(b_f * 255); \
529  \
530  /* float */ \
531                         if(sizeof(type) == 4) \
532                         { \
533                                 r = CLIP(r, 0, 0xff); \
534                                 g = CLIP(g, 0, 0xff); \
535                                 b = CLIP(b, 0, 0xff); \
536                         } \
537  \
538                         draw_point(vector_rows, \
539                                 vector_cmodel, \
540                                 x, \
541                                 y, \
542                                 (int)r, \
543                                 (int)g, \
544                                 (int)b); \
545  \
546                 } \
547         } \
548 }
549
550 void VideoScopeUnit::process_package(LoadPackage *package)
551 {
552         VideoScopeWindow *window = (VideoScopeWindow*)plugin->thread->window;
553         VideoScopePackage *pkg = (VideoScopePackage*)package;
554         int w = plugin->input->get_w();
555 //      int h = plugin->input->get_h();
556         int waveform_h = window->wave_h;
557         int waveform_w = window->wave_w;
558         int waveform_cmodel = window->waveform_bitmap->get_color_model();
559         unsigned char **waveform_rows = window->waveform_bitmap->get_row_pointers();
560         int vector_h = window->vector_bitmap->get_h();
561         int vector_w = window->vector_bitmap->get_w();
562         int vector_cmodel = window->vector_bitmap->get_color_model();
563         unsigned char **vector_rows = window->vector_bitmap->get_row_pointers();
564         float radius = MIN(vector_w / 2, vector_h / 2);
565         int parade = 1;
566
567         switch(plugin->input->get_color_model())
568         {
569                 case BC_RGB888:
570                         VIDEOSCOPE(unsigned char, int, 0xff, 3, 0)
571                         break;
572
573                 case BC_RGB_FLOAT:
574                         VIDEOSCOPE(float, float, 1, 3, 0)
575                         break;
576
577                 case BC_YUV888:
578                         VIDEOSCOPE(unsigned char, int, 0xff, 3, 1)
579                         break;
580
581                 case BC_RGB161616:
582                         VIDEOSCOPE(uint16_t, int, 0xffff, 3, 0)
583                         break;
584
585                 case BC_YUV161616:
586                         VIDEOSCOPE(uint16_t, int, 0xffff, 3, 1)
587                         break;
588
589                 case BC_RGBA8888:
590                         VIDEOSCOPE(unsigned char, int, 0xff, 4, 0)
591                         break;
592
593                 case BC_RGBA_FLOAT:
594                         VIDEOSCOPE(float, float, 1, 4, 0)
595                         break;
596
597                 case BC_YUVA8888:
598                         VIDEOSCOPE(unsigned char, int, 0xff, 4, 1)
599                         break;
600
601                 case BC_RGBA16161616:
602                         VIDEOSCOPE(uint16_t, int, 0xffff, 4, 0)
603                         break;
604
605                 case BC_YUVA16161616:
606                         VIDEOSCOPE(uint16_t, int, 0xffff, 4, 1)
607                         break;
608         }
609 }
610
611
612
613
614
615
616 VideoScopeEngine::VideoScopeEngine(VideoScopeEffect *plugin, int cpus)
617  : LoadServer(cpus, cpus)
618 {
619         this->plugin = plugin;
620 }
621
622 VideoScopeEngine::~VideoScopeEngine()
623 {
624 }
625
626 void VideoScopeEngine::init_packages()
627 {
628         for(int i = 0; i < LoadServer::get_total_packages(); i++)
629         {
630                 VideoScopePackage *pkg = (VideoScopePackage*)get_package(i);
631                 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
632                 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
633         }
634 }
635
636
637 LoadClient* VideoScopeEngine::new_client()
638 {
639         return new VideoScopeUnit(plugin, this);
640 }
641
642 LoadPackage* VideoScopeEngine::new_package()
643 {
644         return new VideoScopePackage;
645 }
646