fix mask vframe setup, add unshared vframe constructor
[goodguy/history.git] / cinelerra-5.1 / plugins / 1080to540 / 1080to540.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 "1080to540.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(_1080to540Main)
42
43
44
45
46 _1080to540Config::_1080to540Config()
47 {
48         first_field = 0;
49 }
50
51 int _1080to540Config::equivalent(_1080to540Config &that)
52 {
53         return first_field == that.first_field;
54 }
55
56 void _1080to540Config::copy_from(_1080to540Config &that)
57 {
58         first_field = that.first_field;
59 }
60
61 void _1080to540Config::interpolate(_1080to540Config &prev,
62         _1080to540Config &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 _1080to540Window::_1080to540Window(_1080to540Main *client)
75  : PluginClientWindow(client,
76         200,
77         100,
78         200,
79         100,
80         0)
81 {
82         this->client = client;
83 }
84
85
86 _1080to540Window::~_1080to540Window()
87 {
88 }
89
90 void _1080to540Window::create_objects()
91 {
92         int x = 10, y = 10;
93
94         add_tool(odd_first = new _1080to540Option(client, this, 1, x, y, _("Odd field first")));
95         y += 25;
96         add_tool(even_first = new _1080to540Option(client, this, 0, x, y, _("Even field first")));
97
98         show_window();
99         flush();
100 }
101
102 int _1080to540Window::set_first_field(int first_field, int send_event)
103 {
104         odd_first->update(first_field == 1);
105         even_first->update(first_field == 0);
106
107
108         if(send_event)
109         {
110                 client->config.first_field = first_field;
111                 client->send_configure_change();
112         }
113         return 0;
114 }
115
116
117
118
119 _1080to540Option::_1080to540Option(_1080to540Main *client,
120                 _1080to540Window *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 _1080to540Option::handle_event()
136 {
137         window->set_first_field(output, 1);
138         return 1;
139 }
140
141
142
143
144
145
146
147
148
149 _1080to540Main::_1080to540Main(PluginServer *server)
150  : PluginVClient(server)
151 {
152
153         temp = 0;
154 }
155
156 _1080to540Main::~_1080to540Main()
157 {
158
159         if(temp) delete temp;
160 }
161
162 const char* _1080to540Main::plugin_title() { return _("1080 to 540"); }
163 int _1080to540Main::is_realtime() { return 1; }
164
165 NEW_WINDOW_MACRO(_1080to540Main, _1080to540Window)
166 LOAD_CONFIGURATION_MACRO(_1080to540Main, _1080to540Config)
167
168
169 #define TEMP_W 854
170 #define TEMP_H 540
171 #define OUT_ROWS 270
172
173 void _1080to540Main::reduce_field(VFrame *output, VFrame *input, int src_field, int dst_field)
174 {
175         int w = input->get_w();
176         int h = input->get_h();
177
178         if(h > output->get_h()) h = output->get_h();
179         if(w > output->get_w()) w = output->get_w();
180
181 #define REDUCE_MACRO(type, temp, components) \
182 for(int i = 0; i < OUT_ROWS; i++) \
183 { \
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; \
189  \
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; \
195  \
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]; \
201  \
202         for(int j = 0; j < w * components; j++) \
203         { \
204                 *out_row++ = ((temp)*in_row1++ +  \
205                         (temp)*in_row2++ +  \
206                         (temp)*in_row3++ +  \
207                         (temp)*in_row4++) / 4; \
208         } \
209 }
210
211         switch(input->get_color_model())
212         {
213                 case BC_RGB888:
214                 case BC_YUV888:
215                         REDUCE_MACRO(unsigned char, int64_t, 3);
216                         break;
217                 case BC_RGB_FLOAT:
218                         REDUCE_MACRO(float, float, 3);
219                         break;
220                 case BC_RGBA8888:
221                 case BC_YUVA8888:
222                         REDUCE_MACRO(unsigned char, int64_t, 4);
223                         break;
224                 case BC_RGBA_FLOAT:
225                         REDUCE_MACRO(float, float, 4);
226                         break;
227                 case BC_RGB161616:
228                 case BC_YUV161616:
229                         REDUCE_MACRO(uint16_t, int64_t, 3);
230                         break;
231                 case BC_RGBA16161616:
232                 case BC_YUVA16161616:
233                         REDUCE_MACRO(uint16_t, int64_t, 4);
234                         break;
235         }
236
237 }
238
239 int _1080to540Main::process_realtime(VFrame *input, VFrame *output)
240 {
241         load_configuration();
242         if(!temp)
243         {
244                 temp = new VFrame(input->get_w(), input->get_h(),
245                         input->get_color_model(), 0);
246                 temp->clear_frame();
247         }
248
249         reduce_field(temp, input, config.first_field == 0 ? 0 : 1, 0);
250         reduce_field(temp, input, config.first_field == 0 ? 1 : 0, 1);
251
252         output->copy_from(temp);
253
254         return 0;
255 }
256
257
258
259 void _1080to540Main::save_data(KeyFrame *keyframe)
260 {
261         FileXML output;
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);
265         output.append_tag();
266         output.tag.set_title("/1080TO540");
267         output.append_tag();
268         output.append_newline();
269         output.terminate_string();
270 }
271
272 void _1080to540Main::read_data(KeyFrame *keyframe)
273 {
274         FileXML input;
275         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
276
277         while(!input.read_tag())
278         {
279                 if(input.tag.title_is("1080TO540"))
280                 {
281                         config.first_field = input.tag.get_property("FIRST_FIELD", config.first_field);
282                 }
283         }
284 }
285
286 void _1080to540Main::update_gui()
287 {
288         if(thread)
289         {
290                 load_configuration();
291                 thread->window->lock_window();
292                 ((_1080to540Window*)thread->window)->set_first_field(config.first_field, 0);
293                 thread->window->unlock_window();
294         }
295 }
296