1f83f499be3f8fc1366df43a9ef45b40f70f5a02
[goodguy/history.git] / cinelerra-5.1 / plugins / 1080to480 / 1080to480.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 "1080to480.h"
23 #include "clip.h"
24 #include "bchash.h"
25 #include "filexml.h"
26 #include "bcdisplayinfo.h"
27 #include "keyframe.h"
28 #include "language.h"
29 #include "overlayframe.h"
30 #include "vframe.h"
31
32
33
34
35
36
37 #include <stdint.h>
38 #include <string.h>
39
40
41 REGISTER_PLUGIN(_1080to480Main)
42
43
44
45
46 _1080to480Config::_1080to480Config()
47 {
48         first_field = 0;
49 }
50
51 int _1080to480Config::equivalent(_1080to480Config &that)
52 {
53         return first_field == that.first_field;
54 }
55
56 void _1080to480Config::copy_from(_1080to480Config &that)
57 {
58         first_field = that.first_field;
59 }
60
61 void _1080to480Config::interpolate(_1080to480Config &prev,
62         _1080to480Config &next,
63         long prev_frame,
64         long next_frame,
65         long current_frame)
66 {
67         copy_from(prev);
68 }
69
70
71
72
73
74 _1080to480Window::_1080to480Window(_1080to480Main *client)
75  : PluginClientWindow(client, 200, 100, 0, 0, 1)
76 {
77         this->client = client;
78 }
79
80
81 _1080to480Window::~_1080to480Window()
82 {
83 }
84
85 void _1080to480Window::create_objects()
86 {
87         int x = 10, y = 10;
88
89         add_tool(odd_first = new _1080to480Option(client, this, 1, x, y, _("Odd field first")));
90         y += 25;
91         add_tool(even_first = new _1080to480Option(client, this, 0, x, y, _("Even field first")));
92
93         show_window();
94         flush();
95 }
96
97 int _1080to480Window::set_first_field(int first_field, int send_event)
98 {
99         odd_first->update(first_field == 1);
100         even_first->update(first_field == 0);
101
102
103         if(send_event)
104         {
105                 client->config.first_field = first_field;
106                 client->send_configure_change();
107         }
108         return 0;
109 }
110
111
112
113
114 _1080to480Option::_1080to480Option(_1080to480Main *client,
115                 _1080to480Window *window,
116                 int output,
117                 int x,
118                 int y,
119                 char *text)
120  : BC_Radial(x,
121         y,
122         client->config.first_field == output,
123         text)
124 {
125         this->client = client;
126         this->window = window;
127         this->output = output;
128 }
129
130 int _1080to480Option::handle_event()
131 {
132         window->set_first_field(output, 1);
133         return 1;
134 }
135
136
137
138
139
140
141
142
143
144
145 _1080to480Main::_1080to480Main(PluginServer *server)
146  : PluginVClient(server)
147 {
148
149         temp = 0;
150 }
151
152 _1080to480Main::~_1080to480Main()
153 {
154
155         if(temp) delete temp;
156 }
157
158 const char* _1080to480Main::plugin_title() { return N_("1080 to 480"); }
159 int _1080to480Main::is_realtime() { return 1; }
160
161 NEW_WINDOW_MACRO(_1080to480Main, _1080to480Window)
162 LOAD_CONFIGURATION_MACRO(_1080to480Main, _1080to480Config)
163
164
165 #define TEMP_W 854
166 #define TEMP_H 480
167 #define OUT_ROWS 270
168
169 void _1080to480Main::reduce_field(VFrame *output, VFrame *input, int src_field, int dst_field)
170 {
171         int w = input->get_w();
172         int h = input->get_h();
173
174         if(h > output->get_h()) h = output->get_h();
175         if(w > output->get_w()) h = output->get_w();
176
177 #define REDUCE_MACRO(type, temp, components) \
178 for(int i = 0; i < OUT_ROWS; i++) \
179 { \
180         int in_number1 = dst_field * 2 + src_field + (int)(i * 2) * 2; \
181         int in_number2 = in_number1 + 2; \
182         int in_number3 = in_number2 + 2; \
183         int in_number4 = in_number3 + 2; \
184         int out_number = dst_field + i * 2; \
185  \
186         if(in_number1 >= h) in_number1 = h - 1; \
187         if(in_number2 >= h) in_number2 = h - 1; \
188         if(in_number3 >= h) in_number3 = h - 1; \
189         if(in_number4 >= h) in_number4 = h - 1; \
190         if(out_number >= h) out_number = h - 1; \
191  \
192         type *in_row1 = (type*)input->get_rows()[in_number1]; \
193         type *in_row2 = (type*)input->get_rows()[in_number2]; \
194         type *in_row3 = (type*)input->get_rows()[in_number3]; \
195         type *in_row4 = (type*)input->get_rows()[in_number4]; \
196         type *out_row = (type*)output->get_rows()[out_number]; \
197  \
198         for(int j = 0; j < w * components; j++) \
199         { \
200                 *out_row++ = ((temp)*in_row1++ +  \
201                         (temp)*in_row2++ +  \
202                         (temp)*in_row3++ +  \
203                         (temp)*in_row4++) / 4; \
204         } \
205 }
206
207         switch(input->get_color_model())
208         {
209                 case BC_RGB888:
210                 case BC_YUV888:
211                         REDUCE_MACRO(unsigned char, int64_t, 3);
212                         break;
213                 case BC_RGB_FLOAT:
214                         REDUCE_MACRO(float, float, 3);
215                         break;
216                 case BC_RGBA8888:
217                 case BC_YUVA8888:
218                         REDUCE_MACRO(unsigned char, int64_t, 4);
219                         break;
220                 case BC_RGBA_FLOAT:
221                         REDUCE_MACRO(float, float, 4);
222                         break;
223                 case BC_RGB161616:
224                 case BC_YUV161616:
225                         REDUCE_MACRO(uint16_t, int64_t, 3);
226                         break;
227                 case BC_RGBA16161616:
228                 case BC_YUVA16161616:
229                         REDUCE_MACRO(uint16_t, int64_t, 4);
230                         break;
231         }
232
233 }
234
235 int _1080to480Main::process_realtime(VFrame *input, VFrame *output)
236 {
237         load_configuration();
238         if(!temp)
239         {
240                 temp = new VFrame(input->get_w(), input->get_h(), input->get_color_model(), 0);
241                 temp->clear_frame();
242         }
243
244         reduce_field(temp, input, config.first_field == 0 ? 0 : 1, 0);
245         reduce_field(temp, input, config.first_field == 0 ? 1 : 0, 1);
246
247         output->copy_from(temp);
248
249         return 0;
250 }
251
252
253 void _1080to480Main::save_data(KeyFrame *keyframe)
254 {
255         FileXML output;
256         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
257         output.tag.set_title("1080TO480");
258         output.tag.set_property("FIRST_FIELD", config.first_field);
259         output.append_tag();
260         output.tag.set_title("/1080TO480");
261         output.append_tag();
262         output.append_newline();
263         output.terminate_string();
264 }
265
266 void _1080to480Main::read_data(KeyFrame *keyframe)
267 {
268         FileXML input;
269         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
270
271         while(!input.read_tag())
272         {
273                 if(input.tag.title_is("1080TO480"))
274                 {
275                         config.first_field = input.tag.get_property("FIRST_FIELD", config.first_field);
276                 }
277         }
278 }
279
280 void _1080to480Main::update_gui()
281 {
282         if(thread)
283         {
284                 load_configuration();
285                 _1080to480Window *window = (_1080to480Window *)thread->window;
286                 window->lock_window();
287                 window->set_first_field(config.first_field, 0);
288                 window->unlock_window();
289         }
290 }
291