add BC_SCALE env var for hi def monitors, cleanup theme data
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / yuv / yuv.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 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 "bccolors.h"
29 #include "pluginvclient.h"
30 #include "theme.h"
31 #include "vframe.h"
32
33 #include <stdint.h>
34 #include <string.h>
35
36 #define RESET_ALL 0
37 #define RESET_Y_SLIDER 1
38 #define RESET_U_SLIDER 2
39 #define RESET_V_SLIDER 3
40
41 class YUVEffect;
42 class YUVWindow;
43 class YUVReset;
44 class YUVSliderClr;
45
46
47 class YUVConfig
48 {
49 public:
50         YUVConfig();
51         void reset(int clear);
52
53         void copy_from(YUVConfig &src);
54         int equivalent(YUVConfig &src);
55         void interpolate(YUVConfig &prev,
56                 YUVConfig &next,
57                 long prev_frame,
58                 long next_frame,
59                 long current_frame);
60
61         float y, u, v;
62 };
63
64 class YUVLevel : public BC_FSlider
65 {
66 public:
67         YUVLevel(YUVEffect *plugin, float *output, int x, int y);
68         int handle_event();
69         YUVEffect *plugin;
70         float *output;
71 };
72
73 class YUVReset : public BC_GenericButton
74 {
75 public:
76         YUVReset(YUVEffect *plugin, YUVWindow *window, int x, int y);
77         ~YUVReset();
78         int handle_event();
79         YUVEffect *plugin;
80         YUVWindow *window;
81 };
82
83 class YUVSliderClr : public BC_Button
84 {
85 public:
86         YUVSliderClr(YUVEffect *plugin, YUVWindow *window, int x, int y, int w, int clear);
87         ~YUVSliderClr();
88         int handle_event();
89         YUVEffect *plugin;
90         YUVWindow *window;
91         int clear;
92 };
93
94 class YUVWindow : public PluginClientWindow
95 {
96 public:
97         YUVWindow(YUVEffect *plugin);
98         void create_objects();
99         void update_gui(int clear);
100         YUVLevel *y, *u, *v;
101         YUVEffect *plugin;
102         YUVReset *reset;
103         YUVSliderClr *yClr, *uClr, *vClr;
104 };
105
106
107
108 class YUVEffect : public PluginVClient
109 {
110 public:
111         YUVEffect(PluginServer *server);
112         ~YUVEffect();
113
114
115         PLUGIN_CLASS_MEMBERS(YUVConfig)
116         int process_realtime(VFrame *input, VFrame *output);
117         int is_realtime();
118         void save_data(KeyFrame *keyframe);
119         void read_data(KeyFrame *keyframe);
120         void update_gui();
121 };
122
123
124
125
126
127 REGISTER_PLUGIN(YUVEffect)
128
129
130
131
132
133
134
135 YUVConfig::YUVConfig()
136 {
137         reset(RESET_ALL);
138 }
139
140 void YUVConfig::reset(int clear)
141 {
142         switch(clear) {
143                 case RESET_Y_SLIDER : y = 0;
144                         break;
145                 case RESET_U_SLIDER : u = 0;
146                         break;
147                 case RESET_V_SLIDER : v = 0;
148                         break;
149                 case RESET_ALL :
150                 default:
151                         y = u = v = 0;
152                         break;
153         }
154 }
155
156 void YUVConfig::copy_from(YUVConfig &src)
157 {
158         y = src.y;
159         u = src.u;
160         v = src.v;
161 }
162
163 int YUVConfig::equivalent(YUVConfig &src)
164 {
165         return EQUIV(y, src.y) && EQUIV(u, src.u) && EQUIV(v, src.v);
166 }
167
168 void YUVConfig::interpolate(YUVConfig &prev,
169         YUVConfig &next,
170         long prev_frame,
171         long next_frame,
172         long current_frame)
173 {
174         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
175         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
176
177         y = prev.y * prev_scale + next.y * next_scale;
178         u = prev.u * prev_scale + next.u * next_scale;
179         v = prev.v * prev_scale + next.v * next_scale;
180 }
181
182
183
184
185
186
187 #define MAXVALUE 100
188
189 YUVLevel::YUVLevel(YUVEffect *plugin, float *output, int x, int y)
190  : BC_FSlider(x,
191                         y,
192                         0,
193                         xS(200),
194                         yS(200),
195                         -MAXVALUE,
196                         MAXVALUE,
197                         *output)
198 {
199         this->plugin = plugin;
200         this->output = output;
201 }
202
203 int YUVLevel::handle_event()
204 {
205         *output = get_value();
206         plugin->send_configure_change();
207         return 1;
208 }
209
210
211 YUVReset::YUVReset(YUVEffect *plugin, YUVWindow *window, int x, int y)
212  : BC_GenericButton(x, y, _("Reset"))
213 {
214         this->plugin = plugin;
215         this->window = window;
216 }
217 YUVReset::~YUVReset()
218 {
219 }
220 int YUVReset::handle_event()
221 {
222         plugin->config.reset(RESET_ALL);
223         window->update_gui(RESET_ALL);
224         plugin->send_configure_change();
225         return 1;
226 }
227
228
229 YUVSliderClr::YUVSliderClr(YUVEffect *plugin, YUVWindow *window, int x, int y, int w, int clear)
230  : BC_Button(x, y, w, plugin->get_theme()->get_image_set("reset_button"))
231 {
232         this->plugin = plugin;
233         this->window = window;
234         this->clear = clear;
235 }
236 YUVSliderClr::~YUVSliderClr()
237 {
238 }
239 int YUVSliderClr::handle_event()
240 {
241         // clear==1 ==> Y slider
242         // clear==2 ==> U slider
243         // clear==3 ==> V slider
244         plugin->config.reset(clear);
245         window->update_gui(clear);
246         plugin->send_configure_change();
247         return 1;
248 }
249
250
251 YUVWindow::YUVWindow(YUVEffect *plugin)
252  : PluginClientWindow(plugin, xS(310), yS(135), xS(310), yS(135), 0)
253 {
254         this->plugin = plugin;
255 }
256
257 void YUVWindow::create_objects()
258 {
259         int xs10 = xS(10), xs40 = xS(40), xs50 = xS(50);
260         int ys10 = yS(10), ys30 = yS(30), ys35 = yS(35);
261         int x = xs10, y = ys10, x1 = xs40;
262         int x2 = 0; int clrBtn_w = xs50;
263
264         add_subwindow(new BC_Title(x, y, _("Y:")));
265         add_subwindow(this->y = new YUVLevel(plugin, &plugin->config.y, x1, y));
266         x2 = x1 + this->y->get_w() + xs10;
267         add_subwindow(yClr = new YUVSliderClr(plugin, this, x2, y, clrBtn_w, RESET_Y_SLIDER));
268
269         y += ys30;
270         add_subwindow(new BC_Title(x, y, _("U:")));
271         add_subwindow(u = new YUVLevel(plugin, &plugin->config.u, x1, y));
272         add_subwindow(uClr = new YUVSliderClr(plugin, this, x2, y, clrBtn_w, RESET_U_SLIDER));
273
274         y += ys30;
275         add_subwindow(new BC_Title(x, y, _("V:")));
276         add_subwindow(v = new YUVLevel(plugin, &plugin->config.v, x1, y));
277         add_subwindow(vClr = new YUVSliderClr(plugin, this, x2, y, clrBtn_w, RESET_V_SLIDER));
278
279         y += ys35;
280         add_subwindow(reset = new YUVReset(plugin, this, x, y));
281
282         show_window();
283         flush();
284 }
285
286
287 // for Reset button
288 void YUVWindow::update_gui(int clear)
289 {
290         switch(clear) {
291                 case RESET_Y_SLIDER : this->y->update(plugin->config.y);
292                         break;
293                 case RESET_U_SLIDER : u->update(plugin->config.u);
294                         break;
295                 case RESET_V_SLIDER : v->update(plugin->config.v);
296                         break;
297                 case RESET_ALL :
298                 default:
299                         this->y->update(plugin->config.y);
300                         u->update(plugin->config.u);
301                         v->update(plugin->config.v);
302                         break;
303         }
304 }
305
306
307
308
309
310
311 YUVEffect::YUVEffect(PluginServer *server)
312  : PluginVClient(server)
313 {
314
315 }
316 YUVEffect::~YUVEffect()
317 {
318
319 }
320
321 const char* YUVEffect::plugin_title() { return N_("YUV"); }
322 int YUVEffect::is_realtime() { return 1; }
323
324
325 NEW_WINDOW_MACRO(YUVEffect, YUVWindow)
326 LOAD_CONFIGURATION_MACRO(YUVEffect, YUVConfig)
327
328 void YUVEffect::update_gui()
329 {
330         if(thread)
331         {
332                 thread->window->lock_window();
333                 load_configuration();
334                 ((YUVWindow*)thread->window)->y->update(config.y);
335                 ((YUVWindow*)thread->window)->u->update(config.u);
336                 ((YUVWindow*)thread->window)->v->update(config.v);
337                 thread->window->unlock_window();
338         }
339 }
340
341 void YUVEffect::save_data(KeyFrame *keyframe)
342 {
343         FileXML output;
344         output.set_shared_output(keyframe->xbuf);
345         output.tag.set_title("YUV");
346         output.tag.set_property("Y", config.y);
347         output.tag.set_property("U", config.u);
348         output.tag.set_property("V", config.v);
349         output.append_tag();
350         output.tag.set_title("/YUV");
351         output.append_tag();
352         output.append_newline();
353         output.terminate_string();
354 }
355
356 void YUVEffect::read_data(KeyFrame *keyframe)
357 {
358         FileXML input;
359         input.set_shared_input(keyframe->xbuf);
360         while(!input.read_tag())
361         {
362                 if(input.tag.title_is("YUV"))
363                 {
364                         config.y = input.tag.get_property("Y", config.y);
365                         config.u = input.tag.get_property("U", config.u);
366                         config.v = input.tag.get_property("V", config.v);
367                 }
368         }
369 }
370
371
372 #define YUV_MACRO(type, temp_type, max, components, use_yuv) \
373 { \
374         for(int i = 0; i < input->get_h(); i++) \
375         { \
376                 type *in_row = (type*)input->get_rows()[i]; \
377                 type *out_row = (type*)output->get_rows()[i]; \
378                 const float round = (sizeof(type) == 4) ? 0.0 : 0.5; \
379  \
380                 for(int j = 0; j < w; j++) \
381                 { \
382                         if(use_yuv) \
383                         { \
384                                 int y = (int)((float)in_row[0] * y_scale + round); \
385                                 int u = (int)((float)(in_row[1] - (max / 2 + 1)) * u_scale + round) + (max / 2 + 1); \
386                                 int v = (int)((float)(in_row[2] - (max / 2 + 1)) * v_scale + round) + (max / 2 + 1); \
387                                 out_row[0] = CLIP(y, 0, max); \
388                                 out_row[1] = CLIP(u, 0, max); \
389                                 out_row[2] = CLIP(v, 0, max); \
390                         } \
391                         else \
392                         { \
393                                 temp_type y, u, v, r, g, b; \
394                                 if(sizeof(type) == 4) \
395                                 { \
396                                         YUV::yuv.rgb_to_yuv_f(in_row[0], in_row[1], in_row[2], y, u, v); \
397                                 } \
398                                 else \
399                                 if(sizeof(type) == 2) \
400                                 { \
401                                         YUV::yuv.rgb_to_yuv_16(in_row[0], in_row[1], in_row[2], y, u, v); \
402                                 } \
403                                 else \
404                                 { \
405                                         YUV::yuv.rgb_to_yuv_8(in_row[0], in_row[1], in_row[2], y, u, v); \
406                                 } \
407  \
408                                 if(sizeof(type) < 4) \
409                                 { \
410                                         CLAMP(y, 0, max); \
411                                         CLAMP(u, 0, max); \
412                                         CLAMP(v, 0, max); \
413  \
414                                         y = temp_type((float)y * y_scale + round); \
415                                         u = temp_type((float)(u - (max / 2 + 1)) * u_scale + round) + (max / 2 + 1); \
416                                         v = temp_type((float)(v - (max / 2 + 1)) * v_scale + round) + (max / 2 + 1); \
417  \
418                                         CLAMP(y, 0, max); \
419                                         CLAMP(u, 0, max); \
420                                         CLAMP(v, 0, max); \
421                                 } \
422                                 else \
423                                 { \
424                                         y = temp_type((float)y * y_scale + round); \
425                                         u = temp_type((float)u * u_scale + round); \
426                                         v = temp_type((float)v * v_scale + round); \
427                                 } \
428  \
429                                 if(sizeof(type) == 4) \
430                                         YUV::yuv.yuv_to_rgb_f(r, g, b, y, u, v); \
431                                 else \
432                                 if(sizeof(type) == 2) \
433                                         YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
434                                 else \
435                                         YUV::yuv.yuv_to_rgb_8(r, g, b, y, u, v); \
436  \
437                                 out_row[0] = r; \
438                                 out_row[1] = g; \
439                                 out_row[2] = b; \
440                         } \
441                  \
442                         in_row += components; \
443                         out_row += components; \
444                 } \
445         } \
446 }
447
448 int YUVEffect::process_realtime(VFrame *input, VFrame *output)
449 {
450         load_configuration();
451
452         if(EQUIV(config.y, 0) && EQUIV(config.u, 0) && EQUIV(config.v, 0))
453         {
454                 if(input->get_rows()[0] != output->get_rows()[0])
455                         output->copy_from(input);
456         }
457         else
458         {
459                 int w = input->get_w();
460
461                 float y_scale = (float)(config.y + MAXVALUE) / MAXVALUE;
462                 float u_scale = (float)(config.u + MAXVALUE) / MAXVALUE;
463                 float v_scale = (float)(config.v + MAXVALUE) / MAXVALUE;
464
465                 if(u_scale > 1) u_scale = 1 + (u_scale - 1) * 4;
466                 if(v_scale > 1) v_scale = 1 + (v_scale - 1) * 4;
467
468                 switch(input->get_color_model())
469                 {
470                         case BC_RGB_FLOAT:
471                                 YUV_MACRO(float, float, 1, 3, 0)
472                                 break;
473
474                         case BC_RGB888:
475                                 YUV_MACRO(unsigned char, int, 0xff, 3, 0)
476                                 break;
477
478                         case BC_YUV888:
479                                 YUV_MACRO(unsigned char, int, 0xff, 3, 1)
480                                 break;
481
482                         case BC_RGB161616:
483                                 YUV_MACRO(uint16_t, int, 0xffff, 3, 0)
484                                 break;
485
486                         case BC_YUV161616:
487                                 YUV_MACRO(uint16_t, int, 0xffff, 3, 1)
488                                 break;
489
490                         case BC_RGBA_FLOAT:
491                                 YUV_MACRO(float, float, 1, 4, 0)
492                                 break;
493
494                         case BC_RGBA8888:
495                                 YUV_MACRO(unsigned char, int, 0xff, 4, 0)
496                                 break;
497
498                         case BC_YUVA8888:
499                                 YUV_MACRO(unsigned char, int, 0xff, 4, 1)
500                                 break;
501
502                         case BC_RGBA16161616:
503                                 YUV_MACRO(uint16_t, int, 0xffff, 4, 0)
504                                 break;
505
506                         case BC_YUVA16161616:
507                                 YUV_MACRO(uint16_t, int, 0xffff, 4, 1)
508                                 break;
509                 }
510
511
512
513         }
514         return 0;
515 }
516
517