Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / plugins / 720to480 / 720to480.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 "720to480.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 "mainprogress.h"
30 #include "vframe.h"
31
32
33 #include <stdint.h>
34 #include <string.h>
35
36
37 REGISTER_PLUGIN(_720to480Main)
38
39
40 #define FORWARD 0
41 #define REVERSE 1
42
43 _720to480Config::_720to480Config()
44 {
45         first_field = 0;
46         direction = FORWARD;
47 }
48
49
50
51
52
53 _720to480Window::_720to480Window(_720to480Main *client, int x, int y)
54  : BC_Window(client->gui_string, 
55         x, 
56         y, 
57         230, 
58         150, 
59         230, 
60         150, 
61         0, 
62         0,
63         1)
64
65         this->client = client; 
66 }
67
68
69 _720to480Window::~_720to480Window()
70 {
71 }
72
73 void _720to480Window::create_objects()
74 {
75         int x = 10, y = 10;
76
77         add_tool(odd_first = new _720to480Order(client, this, 1, x, y, _("Odd field first")));
78         y += 25;
79         add_tool(even_first = new _720to480Order(client, this, 0, x, y, _("Even field first")));
80
81 //      y += 25;
82 //      add_tool(forward = new _720to480Direction(client, this, FORWARD, x, y, _("Downsample")));
83 //      y += 25;
84 //      add_tool(reverse = new _720to480Direction(client, this, REVERSE, x, y, _("Upsample")));
85 // 
86         add_subwindow(new BC_OKButton(this));
87         add_subwindow(new BC_CancelButton(this));
88
89         show_window();
90         flush();
91 }
92
93 int _720to480Window::close_event()
94 {
95         set_done(0);
96         return 1;
97 }
98
99 void _720to480Window::set_first_field(int first_field)
100 {
101         odd_first->update(first_field == 1);
102         even_first->update(first_field == 0);
103
104         client->config.first_field = first_field;
105 }
106
107 void _720to480Window::set_direction(int direction)
108 {
109         forward->update(direction == FORWARD);
110         reverse->update(direction == REVERSE);
111
112
113         client->config.direction = direction;
114 }
115
116
117
118 _720to480Order::_720to480Order(_720to480Main *client, 
119                 _720to480Window *window, 
120                 int output, 
121                 int x, 
122                 int y, 
123                 char *text)
124  : BC_Radial(x, 
125         y, 
126         client->config.first_field == output, 
127         text)
128 {
129         this->client = client;
130         this->window = window;
131         this->output = output;
132 }
133
134 int _720to480Order::handle_event()
135 {
136         window->set_first_field(output);
137         return 1;
138 }
139
140
141
142
143
144 _720to480Direction::_720to480Direction(_720to480Main *client, 
145                 _720to480Window *window, 
146                 int output, 
147                 int x, 
148                 int y, 
149                 char *text)
150  : BC_Radial(x, 
151         y, 
152         client->config.direction == output, 
153         text)
154 {
155         this->client = client;
156         this->window = window;
157         this->output = output;
158 }
159
160 int _720to480Direction::handle_event()
161 {
162         window->set_direction(output);
163         return 1;
164 }
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179 _720to480Main::_720to480Main(PluginServer *server)
180  : PluginVClient(server)
181 {
182         temp = 0;
183 }
184
185 _720to480Main::~_720to480Main()
186 {
187
188         if(temp) delete temp;
189 }
190
191 const char* _720to480Main::plugin_title() { return _("720 to 480"); }
192 int _720to480Main::is_realtime() { return 0; }
193
194 double _720to480Main::get_framerate()
195 {
196         return project_frame_rate / 2;
197 }
198
199
200
201
202
203 int _720to480Main::load_defaults()
204 {
205         char directory[BCTEXTLEN];
206         sprintf(directory, "%s720to480.rc", BCASTDIR);
207         
208         defaults = new BC_Hash(directory);
209         defaults->load();
210         config.first_field = defaults->get("FIRST_FIELD", config.first_field);
211         config.direction = defaults->get("DIRECTION", config.direction);
212         return 0;
213 }
214
215
216 int _720to480Main::save_defaults()
217 {
218         defaults->update("FIRST_FIELD", config.first_field);
219         defaults->update("DIRECTION", config.direction);
220         defaults->save();
221         return 0;
222 }
223
224 int _720to480Main::get_parameters()
225 {
226         BC_DisplayInfo info;
227         _720to480Window window(this, 
228                 info.get_abs_cursor_x(), 
229                 info.get_abs_cursor_y());
230         window.create_objects();
231         int result = window.run_window();
232         return result;
233 }
234
235 int _720to480Main::start_loop()
236 {
237         if(PluginClient::interactive)
238         {
239                 char string[BCTEXTLEN];
240                 sprintf(string, "%s...", plugin_title());
241                 progress = start_progress(string, 
242                         PluginClient::end - PluginClient::start);
243         }
244
245         input_position = PluginClient::start;
246         return 0;
247 }
248
249
250 int _720to480Main::stop_loop()
251 {
252         if(PluginClient::interactive)
253         {
254                 progress->stop_progress();
255                 delete progress;
256         }
257         return 0;
258 }
259
260
261 #define DST_W 854
262 #define DST_H 240
263
264
265 void _720to480Main::reduce_field(VFrame *output, VFrame *input, int dest_row)
266 {
267         int in_w = input->get_w();
268         int in_h = input->get_h();
269         int out_w = output->get_w();
270         int out_h = output->get_h();
271
272 #define REDUCE_MACRO(type, temp, components) \
273 for(int i = 0; i < DST_H; i++) \
274 { \
275         int output_number = dest_row + i * 2; \
276         if(output_number >= out_h) break; \
277  \
278         int in1 = i * 3 + dest_row * 2; \
279         int in2 = i * 3 + 1 + dest_row * 2; \
280         int in3 = i * 3 + 2 + dest_row * 2; \
281  \
282         if(in1 >= in_h) in1 = in_h - 1; \
283         if(in2 >= in_h) in2 = in_h - 1; \
284         if(in3 >= in_h) in3 = in_h - 1; \
285  \
286         type *out_row = (type*)output->get_rows()[output_number]; \
287         type *in_row1 = (type*)input->get_rows()[in1]; \
288         type *in_row2 = (type*)input->get_rows()[in2]; \
289         type *in_row3 = (type*)input->get_rows()[in3]; \
290  \
291         int w = MIN(out_w, in_w) * components; \
292         for(int j = 0; j < w; j++) \
293         { \
294                 *out_row++ = ((temp)*in_row1++ + \
295                         (temp)*in_row2++ + \
296                         (temp)*in_row3++) / 3; \
297         } \
298 }
299
300         switch(input->get_color_model())
301         {
302                 case BC_RGB888:
303                 case BC_YUV888:
304                         REDUCE_MACRO(unsigned char, int64_t, 3);
305                         break;
306                 case BC_RGB_FLOAT:
307                         REDUCE_MACRO(float, float, 3);
308                         break;
309                 case BC_RGBA8888:
310                 case BC_YUVA8888:
311                         REDUCE_MACRO(unsigned char, int64_t, 4);
312                         break;
313                 case BC_RGBA_FLOAT:
314                         REDUCE_MACRO(float, float, 4);
315                         break;
316                 case BC_RGB161616:
317                 case BC_YUV161616:
318                         REDUCE_MACRO(uint16_t, int64_t, 3);
319                         break;
320                 case BC_RGBA16161616:
321                 case BC_YUVA16161616:
322                         REDUCE_MACRO(uint16_t, int64_t, 4);
323                         break;
324         }
325 }
326
327 int _720to480Main::process_loop(VFrame *output)
328 {
329         int result = 0;
330
331         if(!temp)
332                 temp = new VFrame(0,
333                         -1,
334                         output->get_w(),
335                         output->get_h(),
336                         output->get_color_model(),
337                         -1);
338
339         if(config.direction == FORWARD)
340         {
341 // Step 1: Reduce vertically and put in desired fields of output
342                 read_frame(temp, input_position);
343                 reduce_field(output, temp, config.first_field == 0 ? 0 : 1);
344                 input_position++;
345
346                 read_frame(temp, input_position);
347                 reduce_field(output, temp, config.first_field == 0 ? 1 : 0);
348                 input_position++;
349         }
350
351         if(PluginClient::interactive) 
352                 result = progress->update(input_position - PluginClient::start);
353
354         if(input_position >= PluginClient::end) result = 1;
355
356         return result;
357 }
358
359
360
361
362
363
364 void _720to480Main::save_data(KeyFrame *keyframe)
365 {
366         FileXML output;
367         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
368         output.tag.set_title("720TO480");
369         output.tag.set_property("FIRST_FIELD", config.first_field);
370         output.tag.set_property("DIRECTION", config.direction);
371         output.append_tag();
372         output.tag.set_title("/720TO480");
373         output.append_tag();
374         output.append_newline();
375         output.terminate_string();
376 }
377
378 void _720to480Main::read_data(KeyFrame *keyframe)
379 {
380         FileXML input;
381         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
382
383         while(!input.read_tag())
384         {
385                 if(input.tag.title_is("720TO480"))
386                 {
387                         config.first_field = input.tag.get_property("FIRST_FIELD", config.first_field);
388                         config.direction = input.tag.get_property("DIRECTION", config.direction);
389                 }
390         }
391 }
392