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