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