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