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