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