0fbae88f197d966e315a4f40d7c76294b162f87e
[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 "clip.h"
24 #include "bchash.h"
25 #include "filexml.h"
26 #include "guicast.h"
27 #include "language.h"
28 #include "loadbalance.h"
29 #include "bccolors.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.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_to_rgb_16(r, \
420                                                 g, \
421                                                 b, \
422                                                 in_pixel[0], \
423                                                 in_pixel[1], \
424                                                 in_pixel[2]); \
425                                 } \
426                                 else \
427                                 { \
428                                         yuv.yuv_to_rgb_8(r, \
429                                                 g, \
430                                                 b, \
431                                                 in_pixel[0], \
432                                                 in_pixel[1], \
433                                                 in_pixel[2]); \
434                                 } \
435                         } \
436                         else \
437                         { \
438                                 r = in_pixel[0]; \
439                                 g = in_pixel[1]; \
440                                 b = in_pixel[2]; \
441                         } \
442  \
443                         HSV::rgb_to_hsv((float)r / max, \
444                                         (float)g / max, \
445                                         (float)b / max, \
446                                         h, \
447                                         s, \
448                                         v); \
449  \
450 /* Calculate waveform */ \
451                         if(parade) \
452                         { \
453 /* red */ \
454                                 int x = j * waveform_w / w / 3; \
455                                 int y = waveform_h - (int)(((float)r / max - FLOAT_MIN) / \
456                                         (FLOAT_MAX - FLOAT_MIN) * \
457                                         waveform_h); \
458                                 if(x >= 0 && x < waveform_w / 3 && y >= 0 && y < waveform_h) \
459                                         draw_point(waveform_rows, \
460                                                 waveform_cmodel, \
461                                                 x, \
462                                                 y, \
463                                                 0xff, \
464                                                 0x0, \
465                                                 0x0); \
466  \
467 /* green */ \
468                                 x = waveform_w / 3 + j * waveform_w / w / 3; \
469                                 y = waveform_h - (int)(((float)g / max - FLOAT_MIN) / \
470                                         (FLOAT_MAX - FLOAT_MIN) * \
471                                         waveform_h); \
472                                 if(x >= waveform_w / 3 && x < waveform_w * 2 / 3 && \
473                                         y >= 0 && y < waveform_h) \
474                                         draw_point(waveform_rows, \
475                                                 waveform_cmodel, \
476                                                 x, \
477                                                 y, \
478                                                 0x0, \
479                                                 0xff, \
480                                                 0x0); \
481  \
482 /* blue */ \
483                                 x = waveform_w * 2 / 3 + j * waveform_w / w / 3; \
484                                 y = waveform_h - (int)(((float)b / max - FLOAT_MIN) / \
485                                         (FLOAT_MAX - FLOAT_MIN) * \
486                                         waveform_h); \
487                                 if(x >= waveform_w * 2 / 3 && x < waveform_w && \
488                                         y >= 0 && y < waveform_h) \
489                                         draw_point(waveform_rows, \
490                                                 waveform_cmodel, \
491                                                 x, \
492                                                 y, \
493                                                 0x0, \
494                                                 0x0, \
495                                                 0xff); \
496                         } \
497                         else \
498                         { \
499                                 if(!use_yuv) intensity = v; \
500                                 intensity = (intensity - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN) * \
501                                         waveform_h; \
502                                 int y = waveform_h - (int)intensity; \
503                                 int x = j * waveform_w / w; \
504                                 if(x >= 0 && x < waveform_w && y >= 0 && y < waveform_h) \
505                                         draw_point(waveform_rows, \
506                                                 waveform_cmodel, \
507                                                 x, \
508                                                 y, \
509                                                 0xff, \
510                                                 0xff, \
511                                                 0xff); \
512                         } \
513  \
514 /* Calculate vectorscope */ \
515                         float adjacent = cos((h + 90) / 360 * 2 * M_PI); \
516                         float opposite = sin((h + 90) / 360 * 2 * M_PI); \
517                         int x = (int)(vector_w / 2 +  \
518                                 adjacent * (s - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN) * radius); \
519  \
520                         int y = (int)(vector_h / 2 -  \
521                                 opposite * (s - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN) * radius); \
522  \
523  \
524                         CLAMP(x, 0, vector_w - 1); \
525                         CLAMP(y, 0, vector_h - 1); \
526 /* Get color with full saturation & value */ \
527                         float r_f, g_f, b_f; \
528                         HSV::hsv_to_rgb(r_f, \
529                                         g_f, \
530                                         b_f, \
531                                         h, \
532                                         s, \
533                                         1); \
534                         r = (int)(r_f * 255); \
535                         g = (int)(g_f * 255); \
536                         b = (int)(b_f * 255); \
537  \
538  /* float */ \
539                         if(sizeof(type) == 4) \
540                         { \
541                                 r = CLIP(r, 0, 0xff); \
542                                 g = CLIP(g, 0, 0xff); \
543                                 b = CLIP(b, 0, 0xff); \
544                         } \
545  \
546                         draw_point(vector_rows, \
547                                 vector_cmodel, \
548                                 x, \
549                                 y, \
550                                 (int)r, \
551                                 (int)g, \
552                                 (int)b); \
553  \
554                 } \
555         } \
556 }
557
558 void VideoScopeUnit::process_package(LoadPackage *package)
559 {
560         VideoScopeWindow *window = (VideoScopeWindow*)plugin->thread->window;
561         VideoScopePackage *pkg = (VideoScopePackage*)package;
562         int w = plugin->input->get_w();
563 //      int h = plugin->input->get_h();
564         int waveform_h = window->wave_h;
565         int waveform_w = window->wave_w;
566         int waveform_cmodel = window->waveform_bitmap->get_color_model();
567         unsigned char **waveform_rows = window->waveform_bitmap->get_row_pointers();
568         int vector_h = window->vector_bitmap->get_h();
569         int vector_w = window->vector_bitmap->get_w();
570         int vector_cmodel = window->vector_bitmap->get_color_model();
571         unsigned char **vector_rows = window->vector_bitmap->get_row_pointers();
572         float radius = MIN(vector_w / 2, vector_h / 2);
573         int parade = 1;
574
575         switch(plugin->input->get_color_model())
576         {
577                 case BC_RGB888:
578                         VIDEOSCOPE(unsigned char, int, 0xff, 3, 0)
579                         break;
580
581                 case BC_RGB_FLOAT:
582                         VIDEOSCOPE(float, float, 1, 3, 0)
583                         break;
584
585                 case BC_YUV888:
586                         VIDEOSCOPE(unsigned char, int, 0xff, 3, 1)
587                         break;
588
589                 case BC_RGB161616:
590                         VIDEOSCOPE(uint16_t, int, 0xffff, 3, 0)
591                         break;
592
593                 case BC_YUV161616:
594                         VIDEOSCOPE(uint16_t, int, 0xffff, 3, 1)
595                         break;
596
597                 case BC_RGBA8888:
598                         VIDEOSCOPE(unsigned char, int, 0xff, 4, 0)
599                         break;
600
601                 case BC_RGBA_FLOAT:
602                         VIDEOSCOPE(float, float, 1, 4, 0)
603                         break;
604
605                 case BC_YUVA8888:
606                         VIDEOSCOPE(unsigned char, int, 0xff, 4, 1)
607                         break;
608
609                 case BC_RGBA16161616:
610                         VIDEOSCOPE(uint16_t, int, 0xffff, 4, 0)
611                         break;
612
613                 case BC_YUVA16161616:
614                         VIDEOSCOPE(uint16_t, int, 0xffff, 4, 1)
615                         break;
616         }
617 }
618
619
620
621
622
623
624 VideoScopeEngine::VideoScopeEngine(VideoScopeEffect *plugin, int cpus)
625  : LoadServer(cpus, cpus)
626 {
627         this->plugin = plugin;
628 }
629
630 VideoScopeEngine::~VideoScopeEngine()
631 {
632 }
633
634 void VideoScopeEngine::init_packages()
635 {
636         for(int i = 0; i < LoadServer::get_total_packages(); i++)
637         {
638                 VideoScopePackage *pkg = (VideoScopePackage*)get_package(i);
639                 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
640                 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
641         }
642 }
643
644
645 LoadClient* VideoScopeEngine::new_client()
646 {
647         return new VideoScopeUnit(plugin, this);
648 }
649
650 LoadPackage* VideoScopeEngine::new_package()
651 {
652         return new VideoScopePackage;
653 }
654