4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "bcdisplayinfo.h"
28 #include "mainprogress.h"
29 #include "pluginvclient.h"
30 #include "transportque.inc"
36 #define TOP_FIELD_FIRST 0
37 #define BOTTOM_FIELD_FIRST 1
40 class FieldFrameWindow;
48 class FieldFrameConfig
52 int equivalent(FieldFrameConfig &src);
60 class FieldFrameTop : public BC_Radial
63 FieldFrameTop(FieldFrame *plugin, FieldFrameWindow *gui, int x, int y);
66 FieldFrameWindow *gui;
70 class FieldFrameBottom : public BC_Radial
73 FieldFrameBottom(FieldFrame *plugin, FieldFrameWindow *gui, int x, int y);
76 FieldFrameWindow *gui;
79 // class FieldFrameFirst : public BC_Radial
82 // FieldFrameFirst(FieldFrame *plugin, FieldFrameWindow *gui, int x, int y);
83 // int handle_event();
84 // FieldFrame *plugin;
85 // FieldFrameWindow *gui;
88 // class FieldFrameSecond : public BC_Radial
91 // FieldFrameSecond(FieldFrame *plugin, FieldFrameWindow *gui, int x, int y);
92 // int handle_event();
93 // FieldFrame *plugin;
94 // FieldFrameWindow *gui;
97 class FieldFrameWindow : public PluginClientWindow
100 FieldFrameWindow(FieldFrame *plugin);
101 void create_objects();
104 FieldFrameBottom *bottom;
105 // FieldFrameFirst *first;
106 // FieldFrameSecond *second;
114 class FieldFrame : public PluginVClient
117 FieldFrame(PluginServer *server);
120 PLUGIN_CLASS_MEMBERS(FieldFrameConfig);
122 int process_buffer(VFrame *frame,
123 int64_t start_position,
126 void save_data(KeyFrame *keyframe);
127 void read_data(KeyFrame *keyframe);
129 void apply_field(VFrame *output, VFrame *input, int field);
142 REGISTER_PLUGIN(FieldFrame)
147 FieldFrameConfig::FieldFrameConfig()
149 field_dominance = TOP_FIELD_FIRST;
153 int FieldFrameConfig::equivalent(FieldFrameConfig &src)
155 return src.field_dominance == field_dominance &&
156 src.first_frame == first_frame;
166 FieldFrameWindow::FieldFrameWindow(FieldFrame *plugin)
167 : PluginClientWindow(plugin,
174 this->plugin = plugin;
177 void FieldFrameWindow::create_objects()
180 int ys10 = yS(10), ys30 = yS(30);
181 int x = xs10, y = ys10;
182 add_subwindow(top = new FieldFrameTop(plugin, this, x, y));
184 add_subwindow(bottom = new FieldFrameBottom(plugin, this, x, y));
186 // add_subwindow(first = new FieldFrameFirst(plugin, this, x, y));
188 // add_subwindow(second = new FieldFrameSecond(plugin, this, x, y));
206 FieldFrameTop::FieldFrameTop(FieldFrame *plugin,
207 FieldFrameWindow *gui,
212 plugin->config.field_dominance == TOP_FIELD_FIRST,
213 _("Top field first"))
215 this->plugin = plugin;
219 int FieldFrameTop::handle_event()
221 plugin->config.field_dominance = TOP_FIELD_FIRST;
222 gui->bottom->update(0);
223 plugin->send_configure_change();
231 FieldFrameBottom::FieldFrameBottom(FieldFrame *plugin,
232 FieldFrameWindow *gui,
237 plugin->config.field_dominance == BOTTOM_FIELD_FIRST,
238 _("Bottom field first"))
240 this->plugin = plugin;
244 int FieldFrameBottom::handle_event()
246 plugin->config.field_dominance = BOTTOM_FIELD_FIRST;
248 plugin->send_configure_change();
256 // FieldFrameFirst::FieldFrameFirst(FieldFrame *plugin,
257 // FieldFrameWindow *gui,
262 // plugin->config.first_frame == 0,
263 // _("First frame is first field"))
265 // this->plugin = plugin;
269 // int FieldFrameFirst::handle_event()
271 // plugin->config.first_frame = 0;
272 // gui->second->update(0);
273 // plugin->send_configure_change();
280 // FieldFrameSecond::FieldFrameSecond(FieldFrame *plugin,
281 // FieldFrameWindow *gui,
286 // plugin->config.first_frame == 1,
287 // _("Second frame is first field"))
289 // this->plugin = plugin;
293 // int FieldFrameSecond::handle_event()
295 // plugin->config.first_frame = 1;
296 // gui->first->update(0);
297 // plugin->send_configure_change();
322 FieldFrame::FieldFrame(PluginServer *server)
323 : PluginVClient(server)
330 FieldFrame::~FieldFrame()
334 if(input) delete input;
337 const char* FieldFrame::plugin_title() { return N_("Fields to frames"); }
338 int FieldFrame::is_realtime() { return 1; }
341 NEW_WINDOW_MACRO(FieldFrame, FieldFrameWindow)
343 int FieldFrame::load_configuration()
345 KeyFrame *prev_keyframe;
346 FieldFrameConfig old_config = config;
348 prev_keyframe = get_prev_keyframe(get_source_position());
349 read_data(prev_keyframe);
351 return !old_config.equivalent(config);
356 void FieldFrame::save_data(KeyFrame *keyframe)
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);
366 output.tag.set_title("/FIELD_FRAME");
368 output.append_newline();
369 output.terminate_string();
372 void FieldFrame::read_data(KeyFrame *keyframe)
376 input.set_shared_input(keyframe->xbuf);
378 while(!input.read_tag())
380 if(input.tag.title_is("FIELD_FRAME"))
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);
389 void FieldFrame::update_gui()
393 if(load_configuration())
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();
406 int FieldFrame::process_buffer(VFrame *frame,
407 int64_t start_position,
411 load_configuration();
413 if(input && !input->equivalent(frame, 0))
421 input = new VFrame(frame->get_w(), frame->get_h(),
422 frame->get_color_model(), 0);
426 int64_t field1_position = start_position * 2;
427 int64_t field2_position = start_position * 2 + 1;
429 if (get_direction() == PLAY_REVERSE)
431 field1_position -= 1;
432 field2_position -= 1;
436 // printf("FieldFrame::process_buffer %d %lld %lld\n",
437 // config.field_dominance,
447 config.field_dominance == TOP_FIELD_FIRST ? 0 : 1);
455 config.field_dominance == TOP_FIELD_FIRST ? 1 : 0);
465 void FieldFrame::apply_field(VFrame *output, VFrame *input, int field)
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)
472 memcpy(output_rows[i], input_rows[i], row_size);