rework scopewindow, spanish xlat updates
[goodguy/cinelerra.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 N_("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->xbuf);
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->xbuf);
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+ ((p)[1] * 150) + ((p)[2] * 29)) >> 8)
360
361
362 static void draw_point(unsigned char **rows, int color_model,
363                 int x, int y, int r, int g, int b)
364 {
365         switch( color_model ) {
366         case BC_BGR8888: {
367                 unsigned char *pixel = rows[y] + x * 4;
368                 pixel[0] = b; pixel[1] = g; pixel[2] = r;
369                 break;
370         }
371         case BC_BGR888: break;
372         case BC_RGB565: {
373                 unsigned char *pixel = rows[y] + x * 2;
374                 pixel[0] = (r & 0xf8) | (g >> 5);
375                 pixel[1] = ((g & 0xfc) << 5) | (b >> 3);
376                 break;
377         }
378         case BC_BGR565: break;
379         case BC_RGB8: break;
380         }
381 }
382
383 #define VIDEOSCOPE(type, temp_type, max, components, use_yuv) { \
384         for( int i=pkg->row1; i<pkg->row2; ++i ) { \
385                 type *in_row = (type*)plugin->input->get_rows()[i]; \
386                 for( int j=0; j<w; ++j ) { \
387                         type *in_pixel = in_row + j * components; \
388                         float intensity; /* Analyze pixel */ \
389                         if(use_yuv) intensity = (float)*in_pixel / max; \
390                         float h, s, v; \
391                         temp_type r, g, b; \
392                         if( use_yuv ) { \
393                                 if( sizeof(type) == 2 ) { \
394                                         YUV::yuv.yuv_to_rgb_16(r, g, b, \
395                                                 in_pixel[0], in_pixel[1], in_pixel[2]); \
396                                 } \
397                                 else { \
398                                         YUV::yuv.yuv_to_rgb_8(r, g, b, \
399                                                 in_pixel[0], in_pixel[1], in_pixel[2]); \
400                                 } \
401                         } \
402                         else { \
403                                 r = in_pixel[0]; \
404                                 g = in_pixel[1]; \
405                                 b = in_pixel[2]; \
406                         } \
407                         HSV::rgb_to_hsv((float)r / max, (float)g / max, (float)b / max, \
408                                         h, s, v); \
409 /* Calculate waveform */ \
410                         if(parade) { \
411                                 int x = j * waveform_w / w / 3; /* red */ \
412                                 int y = waveform_h - (int)(((float)r / max - FLOAT_MIN) / \
413                                         (FLOAT_MAX - FLOAT_MIN) * waveform_h); \
414                                 if(x >= 0 && x < waveform_w / 3 && y >= 0 && y < waveform_h) \
415                                         draw_point(waveform_rows, waveform_cmodel, x, y, \
416                                                 0xff, 0x00, 0x00); \
417                                 x = waveform_w / 3 + j * waveform_w / w / 3; /* green */ \
418                                 y = waveform_h - (int)(((float)g / max - FLOAT_MIN) / \
419                                         (FLOAT_MAX - FLOAT_MIN) * waveform_h); \
420                                 if(x >= waveform_w / 3 && x < waveform_w * 2 / 3 && \
421                                         y >= 0 && y < waveform_h) \
422                                         draw_point(waveform_rows, waveform_cmodel, x, y, \
423                                                 0x00, 0xff, 0x00); \
424                                 x = waveform_w * 2 / 3 + j * waveform_w / w / 3; /* blue */ \
425                                 y = waveform_h - (int)(((float)b / max - FLOAT_MIN) / \
426                                         (FLOAT_MAX - FLOAT_MIN) * waveform_h); \
427                                 if(x >= waveform_w * 2 / 3 && x < waveform_w && \
428                                         y >= 0 && y < waveform_h) \
429                                         draw_point(waveform_rows, waveform_cmodel, x, y, \
430                                                 0x00, 0x00, 0xff); \
431                         } \
432                         else { \
433                                 if(!use_yuv) intensity = v; \
434                                 intensity = (intensity - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN) * \
435                                         waveform_h; \
436                                 int y = waveform_h - (int)intensity; \
437                                 int x = j * waveform_w / w; \
438                                 if(x >= 0 && x < waveform_w && y >= 0 && y < waveform_h) \
439                                         draw_point(waveform_rows, waveform_cmodel, x, y, \
440                                                 0xff, 0xff, 0xff); \
441                         } \
442 /* Calculate vectorscope */ \
443                         float adjacent = cos((h + 90) / 360 * 2 * M_PI); \
444                         float opposite = sin((h + 90) / 360 * 2 * M_PI); \
445                         int x = (int)(vector_w / 2 +  \
446                                 adjacent * (s - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN) * radius); \
447                         int y = (int)(vector_h / 2 -  \
448                                 opposite * (s - FLOAT_MIN) / (FLOAT_MAX - FLOAT_MIN) * radius); \
449                         CLAMP(x, 0, vector_w - 1); \
450                         CLAMP(y, 0, vector_h - 1); \
451 /* Get color with full saturation & value */ \
452                         float r_f, g_f, b_f; \
453                         HSV::hsv_to_rgb(r_f, g_f, b_f, h, s, 1); \
454                         r = (int)(r_f * 255); \
455                         g = (int)(g_f * 255); \
456                         b = (int)(b_f * 255); \
457                         if(sizeof(type) == 4) { /* float */ \
458                                 r = CLIP(r, 0, 0xff); \
459                                 g = CLIP(g, 0, 0xff); \
460                                 b = CLIP(b, 0, 0xff); \
461                         } \
462                         draw_point(vector_rows, vector_cmodel, x, y, \
463                                 (int)r, (int)g, (int)b); \
464                 } \
465         } \
466 }
467
468 void VideoScopeUnit::process_package(LoadPackage *package)
469 {
470         VideoScopeWindow *window = (VideoScopeWindow*)plugin->thread->window;
471         VideoScopePackage *pkg = (VideoScopePackage*)package;
472         int w = plugin->input->get_w();
473 //      int h = plugin->input->get_h();
474         int waveform_h = window->wave_h;
475         int waveform_w = window->wave_w;
476         int waveform_cmodel = window->waveform_vframe->get_color_model();
477         unsigned char **waveform_rows = window->waveform_vframe->get_rows();
478         int vector_h = window->vector_vframe->get_h();
479         int vector_w = window->vector_vframe->get_w();
480         int vector_cmodel = window->vector_vframe->get_color_model();
481         unsigned char **vector_rows = window->vector_vframe->get_rows();
482         float radius = MIN(vector_w / 2, vector_h / 2);
483         int parade = 1;
484
485         switch( plugin->input->get_color_model() ) {
486         case BC_RGB888:
487                 VIDEOSCOPE(unsigned char, int, 0xff, 3, 0)
488                 break;
489
490         case BC_RGB_FLOAT:
491                 VIDEOSCOPE(float, float, 1, 3, 0)
492                 break;
493
494         case BC_YUV888:
495                 VIDEOSCOPE(unsigned char, int, 0xff, 3, 1)
496                 break;
497
498         case BC_RGB161616:
499                 VIDEOSCOPE(uint16_t, int, 0xffff, 3, 0)
500                 break;
501
502         case BC_YUV161616:
503                 VIDEOSCOPE(uint16_t, int, 0xffff, 3, 1)
504                 break;
505
506         case BC_RGBA8888:
507                 VIDEOSCOPE(unsigned char, int, 0xff, 4, 0)
508                 break;
509
510         case BC_RGBA_FLOAT:
511                 VIDEOSCOPE(float, float, 1, 4, 0)
512                 break;
513
514         case BC_YUVA8888:
515                 VIDEOSCOPE(unsigned char, int, 0xff, 4, 1)
516                 break;
517
518         case BC_RGBA16161616:
519                 VIDEOSCOPE(uint16_t, int, 0xffff, 4, 0)
520                 break;
521
522         case BC_YUVA16161616:
523                 VIDEOSCOPE(uint16_t, int, 0xffff, 4, 1)
524                 break;
525         }
526 }
527
528 VideoScopeEngine::VideoScopeEngine(VideoScopeEffect *plugin, int cpus)
529  : LoadServer(cpus, cpus)
530 {
531         this->plugin = plugin;
532 }
533
534 VideoScopeEngine::~VideoScopeEngine()
535 {
536 }
537
538 void VideoScopeEngine::init_packages()
539 {
540         for(int i = 0; i < LoadServer::get_total_packages(); i++)
541         {
542                 VideoScopePackage *pkg = (VideoScopePackage*)get_package(i);
543                 pkg->row1 = plugin->input->get_h() * i / LoadServer::get_total_packages();
544                 pkg->row2 = plugin->input->get_h() * (i + 1) / LoadServer::get_total_packages();
545         }
546 }
547
548
549 LoadClient* VideoScopeEngine::new_client()
550 {
551         return new VideoScopeUnit(plugin, this);
552 }
553
554 LoadPackage* VideoScopeEngine::new_package()
555 {
556         return new VideoScopePackage;
557 }
558