49e1489b35ef512abe80e8fe2466b147b5b5ef5e
[goodguy/history.git] / cinelerra-5.1 / plugins / downsample / downsample.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 <math.h>
23 #include <stdint.h>
24 #include <string.h>
25
26 #include "bcdisplayinfo.h"
27 #include "clip.h"
28 #include "bchash.h"
29 #include "downsampleengine.h"
30 #include "filexml.h"
31 #include "keyframe.h"
32 #include "language.h"
33 #include "pluginvclient.h"
34 #include "vframe.h"
35
36
37 class DownSampleMain;
38 class DownSampleServer;
39
40
41
42
43
44 class DownSampleConfig
45 {
46 public:
47         DownSampleConfig();
48
49         int equivalent(DownSampleConfig &that);
50         void copy_from(DownSampleConfig &that);
51         void interpolate(DownSampleConfig &prev,
52                 DownSampleConfig &next,
53                 int64_t prev_frame,
54                 int64_t next_frame,
55                 int64_t current_frame);
56
57         int horizontal_x;
58         int vertical_y;
59         int horizontal;
60         int vertical;
61         int r;
62         int g;
63         int b;
64         int a;
65 };
66
67
68 class DownSampleToggle : public BC_CheckBox
69 {
70 public:
71         DownSampleToggle(DownSampleMain *plugin,
72                 int x,
73                 int y,
74                 int *output,
75                 char *string);
76         int handle_event();
77         DownSampleMain *plugin;
78         int *output;
79 };
80
81 class DownSampleSize : public BC_ISlider
82 {
83 public:
84         DownSampleSize(DownSampleMain *plugin,
85                 int x,
86                 int y,
87                 int *output,
88                 int min,
89                 int max);
90         int handle_event();
91         DownSampleMain *plugin;
92         int *output;
93 };
94
95 class DownSampleWindow : public PluginClientWindow
96 {
97 public:
98         DownSampleWindow(DownSampleMain *plugin);
99         ~DownSampleWindow();
100
101         void create_objects();
102
103         DownSampleToggle *r, *g, *b, *a;
104         DownSampleSize *h, *v, *h_x, *v_y;
105         DownSampleMain *plugin;
106 };
107
108
109
110
111
112 class DownSampleMain : public PluginVClient
113 {
114 public:
115         DownSampleMain(PluginServer *server);
116         ~DownSampleMain();
117
118         int process_buffer(VFrame *frame,
119                 int64_t start_position,
120                 double frame_rate);
121         int is_realtime();
122         void save_data(KeyFrame *keyframe);
123         void read_data(KeyFrame *keyframe);
124         void update_gui();
125         int handle_opengl();
126
127         PLUGIN_CLASS_MEMBERS(DownSampleConfig)
128
129         VFrame *input, *output;
130         DownSampleServer *engine;
131 };
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147 REGISTER_PLUGIN(DownSampleMain)
148
149
150
151 DownSampleConfig::DownSampleConfig()
152 {
153         horizontal = 2;
154         vertical = 2;
155         horizontal_x = 0;
156         vertical_y = 0;
157         r = 1;
158         g = 1;
159         b = 1;
160         a = 1;
161 }
162
163 int DownSampleConfig::equivalent(DownSampleConfig &that)
164 {
165         return
166                 horizontal == that.horizontal &&
167                 vertical == that.vertical &&
168                 horizontal_x == that.horizontal_x &&
169                 vertical_y == that.vertical_y &&
170                 r == that.r &&
171                 g == that.g &&
172                 b == that.b &&
173                 a == that.a;
174 }
175
176 void DownSampleConfig::copy_from(DownSampleConfig &that)
177 {
178         horizontal = that.horizontal;
179         vertical = that.vertical;
180         horizontal_x = that.horizontal_x;
181         vertical_y = that.vertical_y;
182         r = that.r;
183         g = that.g;
184         b = that.b;
185         a = that.a;
186 }
187
188 void DownSampleConfig::interpolate(DownSampleConfig &prev,
189         DownSampleConfig &next,
190         int64_t prev_frame,
191         int64_t next_frame,
192         int64_t current_frame)
193 {
194         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
195         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
196         this->horizontal = (int)(prev.horizontal * prev_scale + next.horizontal * next_scale);
197         this->vertical = (int)(prev.vertical * prev_scale + next.vertical * next_scale);
198         this->horizontal_x = (int)(prev.horizontal_x * prev_scale + next.horizontal_x * next_scale);
199         this->vertical_y = (int)(prev.vertical_y * prev_scale + next.vertical_y * next_scale);
200         r = prev.r;
201         g = prev.g;
202         b = prev.b;
203         a = prev.a;
204 }
205
206
207
208
209
210
211
212
213
214
215
216
217 DownSampleWindow::DownSampleWindow(DownSampleMain *plugin)
218  : PluginClientWindow(plugin,
219         230,
220         380,
221         230,
222         380,
223         0)
224 {
225         this->plugin = plugin;
226 }
227
228 DownSampleWindow::~DownSampleWindow()
229 {
230 }
231
232 void DownSampleWindow::create_objects()
233 {
234         int x = 10, y = 10;
235
236         add_subwindow(new BC_Title(x, y, _("Horizontal")));
237         y += 30;
238         add_subwindow(h = new DownSampleSize(plugin,
239                 x,
240                 y,
241                 &plugin->config.horizontal,
242                 1,
243                 100));
244         y += 30;
245         add_subwindow(new BC_Title(x, y, _("Horizontal offset")));
246         y += 30;
247         add_subwindow(h_x = new DownSampleSize(plugin,
248                 x,
249                 y,
250                 &plugin->config.horizontal_x,
251                 0,
252                 100));
253         y += 30;
254         add_subwindow(new BC_Title(x, y, _("Vertical")));
255         y += 30;
256         add_subwindow(v = new DownSampleSize(plugin,
257                 x,
258                 y,
259                 &plugin->config.vertical,
260                 1,
261                 100));
262         y += 30;
263         add_subwindow(new BC_Title(x, y, _("Vertical offset")));
264         y += 30;
265         add_subwindow(v_y = new DownSampleSize(plugin,
266                 x,
267                 y,
268                 &plugin->config.vertical_y,
269                 0,
270                 100));
271         y += 30;
272         add_subwindow(r = new DownSampleToggle(plugin,
273                 x,
274                 y,
275                 &plugin->config.r,
276                 _("Red")));
277         y += 30;
278         add_subwindow(g = new DownSampleToggle(plugin,
279                 x,
280                 y,
281                 &plugin->config.g,
282                 _("Green")));
283         y += 30;
284         add_subwindow(b = new DownSampleToggle(plugin,
285                 x,
286                 y,
287                 &plugin->config.b,
288                 _("Blue")));
289         y += 30;
290         add_subwindow(a = new DownSampleToggle(plugin,
291                 x,
292                 y,
293                 &plugin->config.a,
294                 _("Alpha")));
295         y += 30;
296
297         show_window();
298         flush();
299 }
300
301
302
303
304
305
306
307
308
309
310
311 DownSampleToggle::DownSampleToggle(DownSampleMain *plugin,
312         int x,
313         int y,
314         int *output,
315         char *string)
316  : BC_CheckBox(x, y, *output, string)
317 {
318         this->plugin = plugin;
319         this->output = output;
320 }
321
322 int DownSampleToggle::handle_event()
323 {
324         *output = get_value();
325         plugin->send_configure_change();
326         return 1;
327 }
328
329
330
331
332
333
334
335 DownSampleSize::DownSampleSize(DownSampleMain *plugin,
336         int x,
337         int y,
338         int *output,
339         int min,
340         int max)
341  : BC_ISlider(x, y, 0, 200, 200, min, max, *output)
342 {
343         this->plugin = plugin;
344         this->output = output;
345 }
346 int DownSampleSize::handle_event()
347 {
348         *output = get_value();
349         plugin->send_configure_change();
350         return 1;
351 }
352
353
354
355
356
357
358
359
360
361
362 DownSampleMain::DownSampleMain(PluginServer *server)
363  : PluginVClient(server)
364 {
365
366         engine = 0;
367 }
368
369 DownSampleMain::~DownSampleMain()
370 {
371
372
373         if(engine) delete engine;
374 }
375
376 const char* DownSampleMain::plugin_title() { return _("Downsample"); }
377 int DownSampleMain::is_realtime() { return 1; }
378
379
380 NEW_WINDOW_MACRO(DownSampleMain, DownSampleWindow)
381
382 LOAD_CONFIGURATION_MACRO(DownSampleMain, DownSampleConfig)
383
384
385 int DownSampleMain::process_buffer(VFrame *frame,
386         int64_t start_position,
387         double frame_rate)
388 {
389         this->input = frame;
390         this->output = frame;
391         load_configuration();
392
393 // This can't be done efficiently in a shader because every output pixel
394 // requires summing a large, arbitrary block of the input pixels.
395 // Scaling down a texture wouldn't average every pixel.
396         read_frame(frame, 0, start_position, frame_rate, 0);
397 //              get_use_opengl());
398
399 // Use hardware
400 //      if(get_use_opengl())
401 //      {
402 //              run_opengl();
403 //              return 0;
404 //      }
405
406 // Process in destination
407         if(!engine) engine = new DownSampleServer(get_project_smp() + 1,
408                 get_project_smp() + 1);
409         engine->process_frame(output, output,
410                 config.r, config.g, config.b, config.a,
411                 config.vertical, config.horizontal,
412                 config.vertical_y, config.horizontal_x);
413
414         return 0;
415 }
416
417
418 void DownSampleMain::update_gui()
419 {
420         if(thread)
421         {
422                 load_configuration();
423                 ((DownSampleWindow*)thread->window)->lock_window();
424                 ((DownSampleWindow*)thread->window)->h->update(config.horizontal);
425                 ((DownSampleWindow*)thread->window)->v->update(config.vertical);
426                 ((DownSampleWindow*)thread->window)->h_x->update(config.horizontal_x);
427                 ((DownSampleWindow*)thread->window)->v_y->update(config.vertical_y);
428                 ((DownSampleWindow*)thread->window)->r->update(config.r);
429                 ((DownSampleWindow*)thread->window)->g->update(config.g);
430                 ((DownSampleWindow*)thread->window)->b->update(config.b);
431                 ((DownSampleWindow*)thread->window)->a->update(config.a);
432                 ((DownSampleWindow*)thread->window)->unlock_window();
433         }
434 }
435
436
437
438
439 void DownSampleMain::save_data(KeyFrame *keyframe)
440 {
441         FileXML output;
442
443 // cause data to be stored directly in text
444         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
445         output.tag.set_title("DOWNSAMPLE");
446
447         output.tag.set_property("HORIZONTAL", config.horizontal);
448         output.tag.set_property("VERTICAL", config.vertical);
449         output.tag.set_property("HORIZONTAL_X", config.horizontal_x);
450         output.tag.set_property("VERTICAL_Y", config.vertical_y);
451         output.tag.set_property("R", config.r);
452         output.tag.set_property("G", config.g);
453         output.tag.set_property("B", config.b);
454         output.tag.set_property("A", config.a);
455         output.append_tag();
456         output.tag.set_title("/DOWNSAMPLE");
457         output.append_tag();
458         output.append_newline();
459         output.terminate_string();
460 }
461
462 void DownSampleMain::read_data(KeyFrame *keyframe)
463 {
464         FileXML input;
465         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
466         int result = 0;
467
468         while(!result) {
469                 result = input.read_tag();
470                 if(!result) {
471                         if(input.tag.title_is("DOWNSAMPLE")) {
472                                 config.horizontal = input.tag.get_property("HORIZONTAL", config.horizontal);
473                                 config.vertical = input.tag.get_property("VERTICAL", config.vertical);
474                                 config.horizontal_x = input.tag.get_property("HORIZONTAL_X", config.horizontal_x);
475                                 config.vertical_y = input.tag.get_property("VERTICAL_Y", config.vertical_y);
476                                 config.r = input.tag.get_property("R", config.r);
477                                 config.g = input.tag.get_property("G", config.g);
478                                 config.b = input.tag.get_property("B", config.b);
479                                 config.a = input.tag.get_property("A", config.a);
480                         }
481                 }
482         }
483 }
484
485
486 int DownSampleMain::handle_opengl()
487 {
488 #ifdef HAVE_GL
489         static const char *downsample_frag =
490                 "uniform sampler2D tex;\n"
491                 "uniform float w;\n"
492                 "uniform float h;\n"
493                 "uniform float x_offset;\n"
494                 "uniform float y_offset;\n";
495         (void) downsample_frag; // whatever
496 #endif
497         return 0;
498 }
499
500