improved plugins with added Tumbler box and visible values
[goodguy/cinelerra.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 "yuvshift.h"
23
24
25
26 REGISTER_PLUGIN(YUVShiftEffect)
27
28
29
30
31
32
33 YUVShiftConfig::YUVShiftConfig()
34 {
35         reset(RESET_ALL);
36 }
37
38 void YUVShiftConfig::reset(int clear)
39 {
40         switch(clear) {
41                 case RESET_Y_DX : y_dx = 0;
42                         break;
43                 case RESET_Y_DY : y_dy = 0;
44                         break;
45                 case RESET_U_DX : u_dx = 0;
46                         break;
47                 case RESET_U_DY : u_dy = 0;
48                         break;
49                 case RESET_V_DX : v_dx = 0;
50                         break;
51                 case RESET_V_DY : v_dy = 0;
52                         break;
53                 case RESET_ALL :
54                 default:
55                         y_dx = y_dy = 0;
56                         u_dx = u_dy = 0;
57                         v_dx = v_dy = 0;
58                         break;
59         }
60 }
61
62 void YUVShiftConfig::copy_from(YUVShiftConfig &src)
63 {
64         y_dx = src.y_dx;  y_dy = src.y_dy;
65         u_dx = src.u_dx;  u_dy = src.u_dy;
66         v_dx = src.v_dx;  v_dy = src.v_dy;
67 }
68
69 int YUVShiftConfig::equivalent(YUVShiftConfig &src)
70 {
71         return EQUIV(y_dx, src.y_dx) && EQUIV(u_dx, src.u_dx) && EQUIV(v_dx, src.v_dx) &&
72                 EQUIV(y_dy, src.y_dy) && EQUIV(u_dy, src.u_dy) && EQUIV(v_dy, src.v_dy);
73 }
74
75 void YUVShiftConfig::interpolate(YUVShiftConfig &prev,
76         YUVShiftConfig &next,
77         long prev_frame,
78         long next_frame,
79         long current_frame)
80 {
81         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
82         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
83
84         y_dx = prev.y_dx * prev_scale + next.y_dx * next_scale;
85         y_dy = prev.y_dy * prev_scale + next.y_dy * next_scale;
86         u_dx = prev.u_dx * prev_scale + next.u_dx * next_scale;
87         u_dy = prev.u_dy * prev_scale + next.u_dy * next_scale;
88         v_dx = prev.v_dx * prev_scale + next.v_dx * next_scale;
89         v_dy = prev.v_dy * prev_scale + next.v_dy * next_scale;
90 }
91
92
93
94
95
96
97
98
99
100 YUVShiftIText::YUVShiftIText(YUVShiftWindow *window, YUVShiftEffect *plugin,
101         YUVShiftISlider *slider, int *output, int x, int y, int min, int max)
102  : BC_TumbleTextBox(window, *output,
103         min, max, x, y, xS(60), 0)
104 {
105         this->window = window;
106         this->plugin = plugin;
107         this->output = output;
108         this->slider = slider;
109         this->min = min;
110         this->max = max;
111         set_increment(1);
112 }
113
114 YUVShiftIText::~YUVShiftIText()
115 {
116 }
117
118 int YUVShiftIText::handle_event()
119 {
120         *output = atoi(get_text());
121         if(*output > max) *output = max;
122         if(*output < min) *output = min;
123         slider->update(*output);
124         plugin->send_configure_change();
125         return 1;
126 }
127
128 YUVShiftISlider::YUVShiftISlider(YUVShiftEffect *plugin, YUVShiftIText *text, int *output, int x, int y)
129  : BC_ISlider(x, y, 0, xS(200), xS(200), -MAXVALUE, MAXVALUE, *output)
130 {
131         this->plugin = plugin;
132         this->output = output;
133         this->text = text;
134         enable_show_value(0); // Hide caption
135 }
136
137 int YUVShiftISlider::handle_event()
138 {
139         *output = get_value();
140         text->update((int64_t)*output);
141         plugin->send_configure_change();
142         return 1;
143 }
144
145
146 YUVShiftReset::YUVShiftReset(YUVShiftEffect *plugin, YUVShiftWindow *window, int x, int y)
147  : BC_GenericButton(x, y, _("Reset"))
148 {
149         this->plugin = plugin;
150         this->window = window;
151 }
152 YUVShiftReset::~YUVShiftReset()
153 {
154 }
155 int YUVShiftReset::handle_event()
156 {
157         plugin->config.reset(RESET_ALL);
158         window->update_gui(RESET_ALL);
159         plugin->send_configure_change();
160         return 1;
161 }
162
163
164 YUVShiftClr::YUVShiftClr(YUVShiftEffect *plugin, YUVShiftWindow *window, int x, int y, int clear)
165  : BC_Button(x, y, plugin->get_theme()->get_image_set("reset_button"))
166 {
167         this->plugin = plugin;
168         this->window = window;
169         this->clear = clear;
170 }
171 YUVShiftClr::~YUVShiftClr()
172 {
173 }
174 int YUVShiftClr::handle_event()
175 {
176         // clear==1 ==> y_dx slider --- clear==2 ==> y_dy slider
177         // clear==3 ==> u_dx slider --- clear==4 ==> u_dy slider
178         // clear==5 ==> v_dx slider --- clear==6 ==> v_dy slider
179         plugin->config.reset(clear);
180         window->update_gui(clear);
181         plugin->send_configure_change();
182         return 1;
183 }
184
185
186 YUVShiftWindow::YUVShiftWindow(YUVShiftEffect *plugin)
187  : PluginClientWindow(plugin, xS(420), yS(250), xS(420), yS(250), 0)
188 {
189         this->plugin = plugin;
190 }
191
192 void YUVShiftWindow::create_objects()
193 {
194         int xs10 = xS(10);
195         int ys10 = yS(10), ys30 = yS(30), ys40 = yS(40);
196         int x = xs10, y = ys10;
197         int x2 = xS(80), x3 = xS(180);
198         int clr_x = get_w()-x - xS(22); // note: clrBtn_w = 22
199
200         BC_Bar *bar;
201
202         y += ys10;
203         add_subwindow(new BC_Title(x, y, _("Y_dx:")));
204         y_dx_text = new YUVShiftIText(this, plugin,
205                 0, &plugin->config.y_dx, (x + x2), y, -MAXVALUE, MAXVALUE);
206         y_dx_text->create_objects();
207         y_dx_slider = new YUVShiftISlider(plugin,
208                 y_dx_text, &plugin->config.y_dx, x3, y);
209         add_subwindow(y_dx_slider);
210         y_dx_text->slider = y_dx_slider;
211         clr_x = x3 + y_dx_slider->get_w() + x;
212         add_subwindow(y_dx_Clr = new YUVShiftClr(plugin, this, clr_x, y, RESET_Y_DX));
213         y += ys30;
214
215         add_subwindow(new BC_Title(x, y, _("Y_dy:")));
216         y_dy_text = new YUVShiftIText(this, plugin,
217                 0, &plugin->config.y_dy, (x + x2), y, -MAXVALUE, MAXVALUE);
218         y_dy_text->create_objects();
219         y_dy_slider = new YUVShiftISlider(plugin,
220                 y_dy_text, &plugin->config.y_dy, x3, y);
221         add_subwindow(y_dy_slider);
222         y_dy_text->slider = y_dy_slider;
223         add_subwindow(y_dy_Clr = new YUVShiftClr(plugin, this, clr_x, y, RESET_Y_DY));
224         y += ys30;
225
226         add_subwindow(new BC_Title(x, y, _("U_dx:")));
227         u_dx_text = new YUVShiftIText(this, plugin,
228                 0, &plugin->config.u_dx, (x + x2), y, -MAXVALUE, MAXVALUE);
229         u_dx_text->create_objects();
230         u_dx_slider = new YUVShiftISlider(plugin,
231                 u_dx_text, &plugin->config.u_dx, x3, y);
232         add_subwindow(u_dx_slider);
233         u_dx_text->slider = u_dx_slider;
234         add_subwindow(u_dx_Clr = new YUVShiftClr(plugin, this, clr_x, y, RESET_U_DX));
235         y += ys30;
236
237         add_subwindow(new BC_Title(x, y, _("U_dy:")));
238         u_dy_text = new YUVShiftIText(this, plugin,
239                 0, &plugin->config.u_dy, (x + x2), y, -MAXVALUE, MAXVALUE);
240         u_dy_text->create_objects();
241         u_dy_slider = new YUVShiftISlider(plugin,
242                 u_dy_text, &plugin->config.u_dy, x3, y);
243         add_subwindow(u_dy_slider);
244         u_dy_text->slider = u_dy_slider;
245         add_subwindow(u_dy_Clr = new YUVShiftClr(plugin, this, clr_x, y, RESET_U_DY));
246         y += ys30;
247
248         add_subwindow(new BC_Title(x, y, _("V_dx:")));
249         v_dx_text = new YUVShiftIText(this, plugin,
250                 0, &plugin->config.v_dx, (x + x2), y, -MAXVALUE, MAXVALUE);
251         v_dx_text->create_objects();
252         v_dx_slider = new YUVShiftISlider(plugin,
253                 v_dx_text, &plugin->config.v_dx, x3, y);
254         add_subwindow(v_dx_slider);
255         v_dx_text->slider = v_dx_slider;
256         add_subwindow(v_dx_Clr = new YUVShiftClr(plugin, this, clr_x, y, RESET_V_DX));
257         y += ys30;
258
259         add_subwindow(new BC_Title(x, y, _("V_dy:")));
260         v_dy_text = new YUVShiftIText(this, plugin,
261                 0, &plugin->config.v_dy, (x + x2), y, -MAXVALUE, MAXVALUE);
262         v_dy_text->create_objects();
263         v_dy_slider = new YUVShiftISlider(plugin,
264                 v_dy_text, &plugin->config.v_dy, x3, y);
265         add_subwindow(v_dy_slider);
266         v_dy_text->slider = v_dy_slider;
267         add_subwindow(v_dy_Clr = new YUVShiftClr(plugin, this, clr_x, y, RESET_V_DY));
268         y += ys40;
269
270 // Reset section
271         add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x));
272         y += ys10;
273         add_subwindow(reset = new YUVShiftReset(plugin, this, x, y));
274
275         show_window();
276         flush();
277 }
278
279
280 // for Reset button
281 void YUVShiftWindow::update_gui(int clear)
282 {
283         switch(clear) {
284                 case RESET_Y_DX :
285                         y_dx_text->update((int64_t)plugin->config.y_dx);
286                         y_dx_slider->update(plugin->config.y_dx);
287                         break;
288                 case RESET_Y_DY :
289                         y_dy_text->update((int64_t)plugin->config.y_dy);
290                         y_dy_slider->update(plugin->config.y_dy);
291                         break;
292                 case RESET_U_DX :
293                         u_dx_text->update((int64_t)plugin->config.u_dx);
294                         u_dx_slider->update(plugin->config.u_dx);
295                         break;
296                 case RESET_U_DY :
297                         u_dy_text->update((int64_t)plugin->config.u_dy);
298                         u_dy_slider->update(plugin->config.u_dy);
299                         break;
300                 case RESET_V_DX :
301                         v_dx_text->update((int64_t)plugin->config.v_dx);
302                         v_dx_slider->update(plugin->config.v_dx);
303                         break;
304                 case RESET_V_DY :
305                         v_dy_text->update((int64_t)plugin->config.v_dy);
306                         v_dy_slider->update(plugin->config.v_dy);
307                         break;
308                 case RESET_ALL :
309                 default:
310                         y_dx_text->update((int64_t)plugin->config.y_dx);
311                         y_dx_slider->update(plugin->config.y_dx);
312                         y_dy_text->update((int64_t)plugin->config.y_dy);
313                         y_dy_slider->update(plugin->config.y_dy);
314                         u_dx_text->update((int64_t)plugin->config.u_dx);
315                         u_dx_slider->update(plugin->config.u_dx);
316                         u_dy_text->update((int64_t)plugin->config.u_dy);
317                         u_dy_slider->update(plugin->config.u_dy);
318                         v_dx_text->update((int64_t)plugin->config.v_dx);
319                         v_dx_slider->update(plugin->config.v_dx);
320                         v_dy_text->update((int64_t)plugin->config.v_dy);
321                         v_dy_slider->update(plugin->config.v_dy);
322                         break;
323         }
324 }
325
326
327
328
329
330
331 YUVShiftEffect::YUVShiftEffect(PluginServer *server)
332  : PluginVClient(server)
333 {
334         temp_frame = 0;
335 }
336 YUVShiftEffect::~YUVShiftEffect()
337 {
338         delete temp_frame;
339 }
340
341 const char* YUVShiftEffect::plugin_title() { return N_("YUVShift"); }
342 int YUVShiftEffect::is_realtime() { return 1; }
343
344
345 NEW_WINDOW_MACRO(YUVShiftEffect, YUVShiftWindow)
346 LOAD_CONFIGURATION_MACRO(YUVShiftEffect, YUVShiftConfig)
347
348 void YUVShiftEffect::update_gui()
349 {
350         if(thread)
351         {
352                 YUVShiftWindow *yuv_wdw = (YUVShiftWindow*)thread->window;
353                 yuv_wdw->lock_window("YUVShiftEffect::update_gui");
354                 load_configuration();
355                 yuv_wdw->y_dx_text->update((int64_t)config.y_dx);
356                 yuv_wdw->y_dx_slider->update(config.y_dx);
357                 yuv_wdw->y_dy_text->update((int64_t)config.y_dy);
358                 yuv_wdw->y_dy_slider->update(config.y_dy);
359                 yuv_wdw->u_dx_text->update((int64_t)config.u_dx);
360                 yuv_wdw->u_dx_slider->update(config.u_dx);
361                 yuv_wdw->u_dy_text->update((int64_t)config.u_dy);
362                 yuv_wdw->u_dy_slider->update(config.u_dy);
363                 yuv_wdw->v_dx_text->update((int64_t)config.v_dx);
364                 yuv_wdw->v_dx_slider->update(config.v_dx);
365                 yuv_wdw->v_dy_text->update((int64_t)config.v_dy);
366                 yuv_wdw->v_dy_slider->update(config.v_dy);
367                 yuv_wdw->unlock_window();
368         }
369 }
370
371 void YUVShiftEffect::save_data(KeyFrame *keyframe)
372 {
373         FileXML output;
374         output.set_shared_output(keyframe->xbuf);
375         output.tag.set_title("YUVSHIFT");
376         output.tag.set_property("Y_DX", config.y_dx);
377         output.tag.set_property("Y_DY", config.y_dy);
378         output.tag.set_property("U_DX", config.u_dx);
379         output.tag.set_property("U_DY", config.u_dy);
380         output.tag.set_property("V_DX", config.v_dx);
381         output.tag.set_property("V_DY", config.v_dy);
382         output.append_tag();
383         output.tag.set_title("/YUVSHIFT");
384         output.append_tag();
385         output.append_newline();
386         output.terminate_string();
387 }
388
389 void YUVShiftEffect::read_data(KeyFrame *keyframe)
390 {
391         FileXML input;
392         input.set_shared_input(keyframe->xbuf);
393         while(!input.read_tag())
394         {
395                 if(input.tag.title_is("YUVSHIFT"))
396                 {
397                         config.y_dx = input.tag.get_property("Y_DX", config.y_dx);
398                         config.y_dy = input.tag.get_property("Y_DY", config.y_dy);
399                         config.u_dx = input.tag.get_property("U_DX", config.u_dx);
400                         config.u_dy = input.tag.get_property("U_DY", config.u_dy);
401                         config.v_dx = input.tag.get_property("V_DX", config.v_dx);
402                         config.v_dy = input.tag.get_property("V_DY", config.v_dy);
403                 }
404         }
405 }
406
407
408 #define YUV_MACRO(type, temp_type, components) \
409 { \
410         for(int i = 0; i < h; i++) { \
411                 int yi = i + config.y_dy, ui = i + config.u_dy, vi = i + config.v_dy; \
412                 type *in_y = yi >= 0 && yi < h ? (type *)frame->get_rows()[yi] : 0; \
413                 type *in_u = ui >= 0 && ui < h ? (type *)frame->get_rows()[ui] : 0; \
414                 type *in_v = vi >= 0 && vi < h ? (type *)frame->get_rows()[vi] : 0; \
415                 type *out_row = (type *)output->get_rows()[i]; \
416                 for(int j = 0; j < w; j++) { \
417                         int yj = j + config.y_dx, uj = j + config.u_dx, vj = j + config.v_dx; \
418                         type *yp = in_y && yj >= 0 && yj < w ? in_y + yj*components: 0; \
419                         type *up = in_u && uj >= 0 && uj < w ? in_u + uj*components: 0; \
420                         type *vp = in_v && vj >= 0 && vj < w ? in_v + vj*components: 0; \
421                         out_row[0] = yp ? yp[0] : 0; \
422                         out_row[1] = up ? up[1] : (1<<(8*sizeof(type)-1)); \
423                         out_row[2] = vp ? vp[2] : (1<<(8*sizeof(type)-1)); \
424                         out_row += components; \
425                 } \
426         } \
427 }
428
429 #define RGB_MACRO(type, temp_type, components) \
430 { \
431         for(int i = 0; i < h; i++) { \
432                 int yi = i + config.y_dy, ui = i + config.u_dy, vi = i + config.v_dy; \
433                 uint8_t *in_y = yi >= 0 && yi < h ? (uint8_t *)frame->get_rows()[yi] : 0; \
434                 uint8_t *in_u = ui >= 0 && ui < h ? (uint8_t *)frame->get_rows()[ui] : 0; \
435                 uint8_t *in_v = vi >= 0 && vi < h ? (uint8_t *)frame->get_rows()[vi] : 0; \
436                 type *out_row = (type *)output->get_rows()[i]; \
437                 for(int j = 0; j < w; j++) { \
438                         int yj = j + config.y_dx, uj = j + config.u_dx, vj = j + config.v_dx; \
439                         uint8_t *yp = in_y && yj >= 0 && yj < w ? in_y + yj*3: 0; \
440                         uint8_t *up = in_u && uj >= 0 && uj < w ? in_u + uj*3: 0; \
441                         uint8_t *vp = in_v && vj >= 0 && vj < w ? in_v + vj*3: 0; \
442                         temp_type r, g, b; \
443                         temp_type y = yp ? yp[0] : 0x00; \
444                         temp_type u = up ? up[1] : 0x80; \
445                         temp_type v = vp ? vp[2] : 0x80; \
446                         if( sizeof(type) == 4 ) \
447                                 YUV::yuv.yuv_to_rgb_f(r, g, b, y/255., (u-128.)/255., (v-128.)/255.); \
448                         else if( sizeof(type) == 2 ) \
449                                 YUV::yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
450                         else \
451                                 YUV::yuv.yuv_to_rgb_8(r, g, b, y, u, v); \
452                         out_row[0] = r; \
453                         out_row[1] = g; \
454                         out_row[2] = b; \
455                         out_row += components; \
456                 } \
457         } \
458 }
459
460 int YUVShiftEffect::process_realtime(VFrame *input, VFrame *output)
461 {
462         load_configuration();
463
464         if( EQUIV(config.y_dx, 0) && EQUIV(config.u_dx, 0) && EQUIV(config.v_dx, 0) &&
465                 EQUIV(config.y_dy, 0) && EQUIV(config.u_dy, 0) && EQUIV(config.v_dy, 0) ) {
466                 if(input->get_rows()[0] != output->get_rows()[0])
467                         output->copy_from(input);
468                 return 0;
469         }
470
471         int w = input->get_w(), h = input->get_h();
472         int color_model = input->get_color_model();
473         int is_yuv = BC_CModels::is_yuv(color_model);
474         if( !is_yuv ) color_model = BC_YUV888;
475         VFrame *frame = input;
476         if( input->get_rows()[0] == output->get_rows()[0] || !is_yuv ) {
477                 if( temp_frame && ( temp_frame->get_color_model() != color_model ||
478                         temp_frame->get_w() != w || temp_frame->get_h() != h ) ) {
479                         delete temp_frame;  temp_frame = 0;
480                 }
481                 if( !temp_frame )
482                         temp_frame = new VFrame(w, h, color_model, 0);
483                 frame = temp_frame;
484                 if( color_model != input->get_color_model() )
485                         BC_CModels::transfer(frame->get_rows(), input->get_rows(),
486                                 frame->get_y(), frame->get_u(), frame->get_v(),
487                                 input->get_y(), input->get_u(), input->get_v(),
488                                 0, 0, input->get_w(), input->get_h(),
489                                 0, 0, frame->get_w(), frame->get_h(),
490                                 input->get_color_model(), frame->get_color_model(), 0,
491                                 input->get_bytes_per_line(), w);
492                 else
493                         frame->copy_from(input);
494         }
495
496         switch( input->get_color_model() ) {
497         case BC_YUV888:       YUV_MACRO(unsigned char, int, 3);  break;
498         case BC_YUV161616:    YUV_MACRO(uint16_t, int, 3);       break;
499         case BC_YUVA8888:     YUV_MACRO(unsigned char, int, 4);  break;
500         case BC_YUVA16161616: YUV_MACRO(uint16_t, int, 4);       break;
501         case BC_RGB_FLOAT:    RGB_MACRO(float, float, 3);        break;
502         case BC_RGB888:       RGB_MACRO(unsigned char, int, 3);  break;
503         case BC_RGB161616:    RGB_MACRO(uint16_t, int, 3);       break;
504         case BC_RGBA_FLOAT:   RGB_MACRO(float, float, 4);        break;
505         case BC_RGBA8888:     RGB_MACRO(unsigned char, int, 4);  break;
506         case BC_RGBA16161616: RGB_MACRO(uint16_t, int, 4);       break;
507         }
508
509         return 0;
510 }
511
512