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