2880a9ebe7597d67c65ae5236949d7322d8de6a4
[goodguy/history.git] / cinelerra-5.0 / 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->get_data(), MESSAGESIZE);
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.append_newline();
286         output.terminate_string();
287 // data is now in *text
288 }
289
290 void ShiftInterlaceMain::read_data(KeyFrame *keyframe)
291 {
292         FileXML input;
293
294         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
295
296         int result = 0;
297
298         while(!result)
299         {
300                 result = input.read_tag();
301
302                 if(!result)
303                 {
304                         if(input.tag.title_is("SHIFTINTERLACE"))
305                         {
306                                 config.odd_offset = input.tag.get_property("ODD_OFFSET", config.odd_offset);
307                                 config.even_offset = input.tag.get_property("EVEN_OFFSET", config.even_offset);
308                         }
309                 }
310         }
311 }
312
313 void ShiftInterlaceMain::update_gui()
314 {
315         if(thread) 
316         {
317                 load_configuration();
318                 thread->window->lock_window();
319                 ((ShiftInterlaceWindow*)thread->window)->odd_offset->update(config.odd_offset);
320                 ((ShiftInterlaceWindow*)thread->window)->even_offset->update(config.even_offset);
321                 thread->window->unlock_window();
322         }
323 }
324
325
326 #define SHIFT_ROW_MACRO(components, type, chroma_offset) \
327 { \
328         type *input_row = (type*)input_frame->get_rows()[row]; \
329         type *output_row = (type*)output_frame->get_rows()[row]; \
330  \
331         if(offset < 0) \
332         { \
333                 int i, j; \
334                 for(i = 0, j = -offset;  \
335                         j < w;  \
336                         i++, j++) \
337                 { \
338                         output_row[i * components + 0] = input_row[j * components + 0]; \
339                         output_row[i * components + 1] = input_row[j * components + 1]; \
340                         output_row[i * components + 2] = input_row[j * components + 2]; \
341                         if(components == 4) output_row[i * components + 3] = input_row[j * components + 3]; \
342                 } \
343  \
344                 for( ; i < w; i++) \
345                 { \
346                         output_row[i * components + 0] = 0; \
347                         output_row[i * components + 1] = chroma_offset; \
348                         output_row[i * components + 2] = chroma_offset; \
349                         if(components == 4) output_row[i * components + 3] = 0; \
350                 } \
351         } \
352         else \
353         { \
354                 int i, j; \
355                 for(i = w - offset - 1, j = w - 1; \
356                         j >= offset; \
357                         i--, \
358                         j--) \
359                 { \
360                         output_row[j * components + 0] = input_row[i * components + 0]; \
361                         output_row[j * components + 1] = input_row[i * components + 1]; \
362                         output_row[j * components + 2] = input_row[i * components + 2]; \
363                         if(components == 4) output_row[j * components + 3] = input_row[i * components + 3]; \
364                 } \
365  \
366                 for( ; j >= 0; j--) \
367                 { \
368                         output_row[j * components + 0] = 0; \
369                         output_row[j * components + 1] = chroma_offset; \
370                         output_row[j * components + 2] = chroma_offset; \
371                         if(components == 4) output_row[j * components + 3] = 0; \
372                 } \
373         } \
374 }
375
376
377 void ShiftInterlaceMain::shift_row(VFrame *input_frame, 
378         VFrame *output_frame,
379         int offset,
380         int row)
381 {
382         int w = input_frame->get_w();
383         switch(input_frame->get_color_model())
384         {
385                 case BC_RGB888:
386                         SHIFT_ROW_MACRO(3, unsigned char, 0x0)
387                         break;
388                 case BC_RGB_FLOAT:
389                         SHIFT_ROW_MACRO(3, float, 0x0)
390                         break;
391                 case BC_YUV888:
392                         SHIFT_ROW_MACRO(3, unsigned char, 0x80)
393                         break;
394                 case BC_RGBA_FLOAT:
395                         SHIFT_ROW_MACRO(4, float, 0x0)
396                         break;
397                 case BC_RGBA8888:
398                         SHIFT_ROW_MACRO(4, unsigned char, 0x0)
399                         break;
400                 case BC_YUVA8888:
401                         SHIFT_ROW_MACRO(4, unsigned char, 0x80)
402                         break;
403                 case BC_RGB161616:
404                         SHIFT_ROW_MACRO(3, uint16_t, 0x0)
405                         break;
406                 case BC_YUV161616:
407                         SHIFT_ROW_MACRO(3, uint16_t, 0x8000)
408                         break;
409                 case BC_RGBA16161616:
410                         SHIFT_ROW_MACRO(4, uint16_t, 0x0)
411                         break;
412                 case BC_YUVA16161616:
413                         SHIFT_ROW_MACRO(4, uint16_t, 0x8000)
414                         break;
415         }
416 }
417
418 int ShiftInterlaceMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
419 {
420         load_configuration();
421
422         int h = input_ptr->get_h();
423         for(int i = 0; i < h; i++)
424         {
425                 if(i % 2)
426                         shift_row(input_ptr, output_ptr, config.even_offset, i);
427                 else
428                         shift_row(input_ptr, output_ptr, config.odd_offset, i);
429         }
430
431         return 0;
432 }
433
434