58449ff56c7563b752e7e535d2f82a9b54161e42
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / fieldframe / fieldframe.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 "bchash.h"
24 #include "filexml.h"
25 #include "guicast.h"
26 #include "keyframe.h"
27 #include "language.h"
28 #include "mainprogress.h"
29 #include "pluginvclient.h"
30 #include "transportque.inc"
31 #include "vframe.h"
32
33 #include <string.h>
34
35
36 #define TOP_FIELD_FIRST 0
37 #define BOTTOM_FIELD_FIRST 1
38
39 class FieldFrame;
40 class FieldFrameWindow;
41
42
43
44
45
46
47
48 class FieldFrameConfig
49 {
50 public:
51         FieldFrameConfig();
52         int equivalent(FieldFrameConfig &src);
53         int field_dominance;
54         int first_frame;
55 };
56
57
58
59
60 class FieldFrameTop : public BC_Radial
61 {
62 public:
63         FieldFrameTop(FieldFrame *plugin, FieldFrameWindow *gui, int x, int y);
64         int handle_event();
65         FieldFrame *plugin;
66         FieldFrameWindow *gui;
67 };
68
69
70 class FieldFrameBottom : public BC_Radial
71 {
72 public:
73         FieldFrameBottom(FieldFrame *plugin, FieldFrameWindow *gui, int x, int y);
74         int handle_event();
75         FieldFrame *plugin;
76         FieldFrameWindow *gui;
77 };
78
79 // class FieldFrameFirst : public BC_Radial
80 // {
81 // public:
82 //      FieldFrameFirst(FieldFrame *plugin, FieldFrameWindow *gui, int x, int y);
83 //      int handle_event();
84 //      FieldFrame *plugin;
85 //      FieldFrameWindow *gui;
86 // };
87 //
88 // class FieldFrameSecond : public BC_Radial
89 // {
90 // public:
91 //      FieldFrameSecond(FieldFrame *plugin, FieldFrameWindow *gui, int x, int y);
92 //      int handle_event();
93 //      FieldFrame *plugin;
94 //      FieldFrameWindow *gui;
95 // };
96
97 class FieldFrameWindow : public PluginClientWindow
98 {
99 public:
100         FieldFrameWindow(FieldFrame *plugin);
101         void create_objects();
102         FieldFrame *plugin;
103         FieldFrameTop *top;
104         FieldFrameBottom *bottom;
105 //      FieldFrameFirst *first;
106 //      FieldFrameSecond *second;
107 };
108
109
110
111
112
113
114 class FieldFrame : public PluginVClient
115 {
116 public:
117         FieldFrame(PluginServer *server);
118         ~FieldFrame();
119
120         PLUGIN_CLASS_MEMBERS(FieldFrameConfig);
121
122         int process_buffer(VFrame *frame,
123                 int64_t start_position,
124                 double frame_rate);
125         int is_realtime();
126         void save_data(KeyFrame *keyframe);
127         void read_data(KeyFrame *keyframe);
128         void update_gui();
129         void apply_field(VFrame *output, VFrame *input, int field);
130
131
132         VFrame *input;
133 };
134
135
136
137
138
139
140
141
142 REGISTER_PLUGIN(FieldFrame)
143
144
145
146
147 FieldFrameConfig::FieldFrameConfig()
148 {
149         field_dominance = TOP_FIELD_FIRST;
150         first_frame = 0;
151 }
152
153 int FieldFrameConfig::equivalent(FieldFrameConfig &src)
154 {
155         return src.field_dominance == field_dominance &&
156                 src.first_frame == first_frame;
157 }
158
159
160
161
162
163
164
165
166 FieldFrameWindow::FieldFrameWindow(FieldFrame *plugin)
167  : PluginClientWindow(plugin,
168         xS(230),
169         yS(100),
170         xS(230),
171         yS(100),
172         0)
173 {
174         this->plugin = plugin;
175 }
176
177 void FieldFrameWindow::create_objects()
178 {
179         int xs10 = xS(10);
180         int ys10 = yS(10), ys30 = yS(30);
181         int x = xs10, y = ys10;
182         add_subwindow(top = new FieldFrameTop(plugin, this, x, y));
183         y += ys30;
184         add_subwindow(bottom = new FieldFrameBottom(plugin, this, x, y));
185 //      y += ys30;
186 //      add_subwindow(first = new FieldFrameFirst(plugin, this, x, y));
187 //      y += ys30;
188 //      add_subwindow(second = new FieldFrameSecond(plugin, this, x, y));
189
190         show_window();
191         flush();
192 }
193
194
195
196
197
198
199
200
201
202
203
204
205
206 FieldFrameTop::FieldFrameTop(FieldFrame *plugin,
207         FieldFrameWindow *gui,
208         int x,
209         int y)
210  : BC_Radial(x,
211         y,
212         plugin->config.field_dominance == TOP_FIELD_FIRST,
213         _("Top field first"))
214 {
215         this->plugin = plugin;
216         this->gui = gui;
217 }
218
219 int FieldFrameTop::handle_event()
220 {
221         plugin->config.field_dominance = TOP_FIELD_FIRST;
222         gui->bottom->update(0);
223         plugin->send_configure_change();
224         return 1;
225 }
226
227
228
229
230
231 FieldFrameBottom::FieldFrameBottom(FieldFrame *plugin,
232         FieldFrameWindow *gui,
233         int x,
234         int y)
235  : BC_Radial(x,
236         y,
237         plugin->config.field_dominance == BOTTOM_FIELD_FIRST,
238         _("Bottom field first"))
239 {
240         this->plugin = plugin;
241         this->gui = gui;
242 }
243
244 int FieldFrameBottom::handle_event()
245 {
246         plugin->config.field_dominance = BOTTOM_FIELD_FIRST;
247         gui->top->update(0);
248         plugin->send_configure_change();
249         return 1;
250 }
251
252
253
254
255
256 // FieldFrameFirst::FieldFrameFirst(FieldFrame *plugin,
257 //      FieldFrameWindow *gui,
258 //      int x,
259 //      int y)
260 //  : BC_Radial(x,
261 //      y,
262 //      plugin->config.first_frame == 0,
263 //      _("First frame is first field"))
264 // {
265 //      this->plugin = plugin;
266 //      this->gui = gui;
267 // }
268 //
269 // int FieldFrameFirst::handle_event()
270 // {
271 //      plugin->config.first_frame = 0;
272 //      gui->second->update(0);
273 //      plugin->send_configure_change();
274 //      return 1;
275 // }
276 //
277 //
278 //
279 //
280 // FieldFrameSecond::FieldFrameSecond(FieldFrame *plugin,
281 //      FieldFrameWindow *gui,
282 //      int x,
283 //      int y)
284 //  : BC_Radial(x,
285 //      y,
286 //      plugin->config.first_frame == 1,
287 //      _("Second frame is first field"))
288 // {
289 //      this->plugin = plugin;
290 //      this->gui = gui;
291 // }
292 //
293 // int FieldFrameSecond::handle_event()
294 // {
295 //      plugin->config.first_frame = 1;
296 //      gui->first->update(0);
297 //      plugin->send_configure_change();
298 //      return 1;
299 // }
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322 FieldFrame::FieldFrame(PluginServer *server)
323  : PluginVClient(server)
324 {
325
326         input = 0;
327 }
328
329
330 FieldFrame::~FieldFrame()
331 {
332
333
334         if(input) delete input;
335 }
336
337 const char* FieldFrame::plugin_title() { return N_("Fields to frames"); }
338 int FieldFrame::is_realtime() { return 1; }
339
340
341 NEW_WINDOW_MACRO(FieldFrame, FieldFrameWindow)
342
343 int FieldFrame::load_configuration()
344 {
345         KeyFrame *prev_keyframe;
346         FieldFrameConfig old_config = config;
347
348         prev_keyframe = get_prev_keyframe(get_source_position());
349         read_data(prev_keyframe);
350
351         return !old_config.equivalent(config);
352 }
353
354
355
356 void FieldFrame::save_data(KeyFrame *keyframe)
357 {
358         FileXML output;
359
360 // cause data to be stored directly in text
361         output.set_shared_output(keyframe->xbuf);
362         output.tag.set_title("FIELD_FRAME");
363         output.tag.set_property("DOMINANCE", config.field_dominance);
364         output.tag.set_property("FIRST_FRAME", config.first_frame);
365         output.append_tag();
366         output.tag.set_title("/FIELD_FRAME");
367         output.append_tag();
368         output.append_newline();
369         output.terminate_string();
370 }
371
372 void FieldFrame::read_data(KeyFrame *keyframe)
373 {
374         FileXML input;
375
376         input.set_shared_input(keyframe->xbuf);
377
378         while(!input.read_tag())
379         {
380                 if(input.tag.title_is("FIELD_FRAME"))
381                 {
382                         config.field_dominance = input.tag.get_property("DOMINANCE", config.field_dominance);
383                         config.first_frame = input.tag.get_property("FIRST_FRAME", config.first_frame);
384                 }
385         }
386 }
387
388
389 void FieldFrame::update_gui()
390 {
391         if(thread)
392         {
393                 if(load_configuration())
394                 {
395                         thread->window->lock_window();
396                         ((FieldFrameWindow*)thread->window)->top->update(config.field_dominance == TOP_FIELD_FIRST);
397                         ((FieldFrameWindow*)thread->window)->bottom->update(config.field_dominance == BOTTOM_FIELD_FIRST);
398 //                      thread->window->first->update(config.first_frame == 0);
399 //                      thread->window->second->update(config.first_frame == 1);
400                         thread->window->unlock_window();
401                 }
402         }
403 }
404
405
406 int FieldFrame::process_buffer(VFrame *frame,
407                 int64_t start_position,
408                 double frame_rate)
409 {
410         int result = 0;
411         load_configuration();
412
413         if(input && !input->equivalent(frame, 0))
414         {
415                 delete input;
416                 input = 0;
417         }
418
419         if(!input)
420         {
421                 input = new VFrame(frame->get_w(), frame->get_h(),
422                                 frame->get_color_model(), 0);
423         }
424
425 // Get input frames
426         int64_t field1_position = start_position * 2;
427         int64_t field2_position = start_position * 2 + 1;
428
429         if (get_direction() == PLAY_REVERSE)
430         {
431                 field1_position -= 1;
432                 field2_position -= 1;
433         }
434
435
436 // printf("FieldFrame::process_buffer %d %lld %lld\n",
437 // config.field_dominance,
438 // field1_position,
439 // field2_position);
440         read_frame(input,
441                 0,
442                 field1_position,
443                 frame_rate * 2,
444                 0);
445         apply_field(frame,
446                 input,
447                 config.field_dominance == TOP_FIELD_FIRST ? 0 : 1);
448         read_frame(input,
449                 0,
450                 field2_position,
451                 frame_rate * 2,
452                 0);
453         apply_field(frame,
454                 input,
455                 config.field_dominance == TOP_FIELD_FIRST ? 1 : 0);
456
457
458
459
460
461         return result;
462 }
463
464
465 void FieldFrame::apply_field(VFrame *output, VFrame *input, int field)
466 {
467         unsigned char **input_rows = input->get_rows();
468         unsigned char **output_rows = output->get_rows();
469         int row_size = VFrame::calculate_bytes_per_pixel(output->get_color_model()) * output->get_w();
470         for(int i = field; i < output->get_h(); i += 2)
471         {
472                 memcpy(output_rows[i], input_rows[i], row_size);
473         }
474 }