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 "1080to540.h"
26 #include "bcdisplayinfo.h"
29 #include "overlayframe.h"
41 REGISTER_PLUGIN(_1080to540Main)
46 _1080to540Config::_1080to540Config()
51 int _1080to540Config::equivalent(_1080to540Config &that)
53 return first_field == that.first_field;
56 void _1080to540Config::copy_from(_1080to540Config &that)
58 first_field = that.first_field;
61 void _1080to540Config::interpolate(_1080to540Config &prev,
62 _1080to540Config &next,
74 _1080to540Window::_1080to540Window(_1080to540Main *client)
75 : PluginClientWindow(client,
82 this->client = client;
86 _1080to540Window::~_1080to540Window()
90 void _1080to540Window::create_objects()
94 add_tool(odd_first = new _1080to540Option(client, this, 1, x, y, _("Odd field first")));
96 add_tool(even_first = new _1080to540Option(client, this, 0, x, y, _("Even field first")));
102 int _1080to540Window::set_first_field(int first_field, int send_event)
104 odd_first->update(first_field == 1);
105 even_first->update(first_field == 0);
110 client->config.first_field = first_field;
111 client->send_configure_change();
119 _1080to540Option::_1080to540Option(_1080to540Main *client,
120 _1080to540Window *window,
127 client->config.first_field == output,
130 this->client = client;
131 this->window = window;
132 this->output = output;
135 int _1080to540Option::handle_event()
137 window->set_first_field(output, 1);
149 _1080to540Main::_1080to540Main(PluginServer *server)
150 : PluginVClient(server)
156 _1080to540Main::~_1080to540Main()
159 if(temp) delete temp;
162 const char* _1080to540Main::plugin_title() { return N_("1080 to 540"); }
163 int _1080to540Main::is_realtime() { return 1; }
165 NEW_WINDOW_MACRO(_1080to540Main, _1080to540Window)
166 LOAD_CONFIGURATION_MACRO(_1080to540Main, _1080to540Config)
173 void _1080to540Main::reduce_field(VFrame *output, VFrame *input, int src_field, int dst_field)
175 int w = input->get_w();
176 int h = input->get_h();
178 if(h > output->get_h()) h = output->get_h();
179 if(w > output->get_w()) w = output->get_w();
181 #define REDUCE_MACRO(type, temp, components) \
182 for(int i = 0; i < OUT_ROWS; i++) \
184 int in_number1 = dst_field * 2 + src_field + (int)(i * 2) * 2; \
185 int in_number2 = in_number1 + 2; \
186 int in_number3 = in_number2 + 2; \
187 int in_number4 = in_number3 + 2; \
188 int out_number = dst_field + i * 2; \
190 if(in_number1 >= h) in_number1 = h - 1; \
191 if(in_number2 >= h) in_number2 = h - 1; \
192 if(in_number3 >= h) in_number3 = h - 1; \
193 if(in_number4 >= h) in_number4 = h - 1; \
194 if(out_number >= h) out_number = h - 1; \
196 type *in_row1 = (type*)input->get_rows()[in_number1]; \
197 type *in_row2 = (type*)input->get_rows()[in_number2]; \
198 type *in_row3 = (type*)input->get_rows()[in_number3]; \
199 type *in_row4 = (type*)input->get_rows()[in_number4]; \
200 type *out_row = (type*)output->get_rows()[out_number]; \
202 for(int j = 0; j < w * components; j++) \
204 *out_row++ = ((temp)*in_row1++ + \
207 (temp)*in_row4++) / 4; \
211 switch(input->get_color_model())
215 REDUCE_MACRO(unsigned char, int64_t, 3);
218 REDUCE_MACRO(float, float, 3);
222 REDUCE_MACRO(unsigned char, int64_t, 4);
225 REDUCE_MACRO(float, float, 4);
229 REDUCE_MACRO(uint16_t, int64_t, 3);
231 case BC_RGBA16161616:
232 case BC_YUVA16161616:
233 REDUCE_MACRO(uint16_t, int64_t, 4);
239 int _1080to540Main::process_realtime(VFrame *input, VFrame *output)
241 load_configuration();
244 temp = new VFrame(input->get_w(), input->get_h(),
245 input->get_color_model(), 0);
249 reduce_field(temp, input, config.first_field == 0 ? 0 : 1, 0);
250 reduce_field(temp, input, config.first_field == 0 ? 1 : 0, 1);
252 output->copy_from(temp);
259 void _1080to540Main::save_data(KeyFrame *keyframe)
262 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
263 output.tag.set_title("1080TO540");
264 output.tag.set_property("FIRST_FIELD", config.first_field);
266 output.tag.set_title("/1080TO540");
268 output.append_newline();
269 output.terminate_string();
272 void _1080to540Main::read_data(KeyFrame *keyframe)
275 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
277 while(!input.read_tag())
279 if(input.tag.title_is("1080TO540"))
281 config.first_field = input.tag.get_property("FIRST_FIELD", config.first_field);
286 void _1080to540Main::update_gui()
290 load_configuration();
291 thread->window->lock_window();
292 ((_1080to540Window*)thread->window)->set_first_field(config.first_field, 0);
293 thread->window->unlock_window();