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