Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.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         xS(230),
220         yS(380),
221         xS(230),
222         yS(380),
223         0)
224 {
225         this->plugin = plugin;
226 }
227
228 DownSampleWindow::~DownSampleWindow()
229 {
230 }
231
232 void DownSampleWindow::create_objects()
233 {
234         int xs10 = xS(10);
235         int ys10 = yS(10), ys30 = yS(30);
236         int x = xs10, y = ys10;
237
238         add_subwindow(new BC_Title(x, y, _("Horizontal")));
239         y += ys30;
240         add_subwindow(h = new DownSampleSize(plugin,
241                 x,
242                 y,
243                 &plugin->config.horizontal,
244                 1,
245                 100));
246         y += ys30;
247         add_subwindow(new BC_Title(x, y, _("Horizontal offset")));
248         y += ys30;
249         add_subwindow(h_x = new DownSampleSize(plugin,
250                 x,
251                 y,
252                 &plugin->config.horizontal_x,
253                 0,
254                 100));
255         y += ys30;
256         add_subwindow(new BC_Title(x, y, _("Vertical")));
257         y += ys30;
258         add_subwindow(v = new DownSampleSize(plugin,
259                 x,
260                 y,
261                 &plugin->config.vertical,
262                 1,
263                 100));
264         y += ys30;
265         add_subwindow(new BC_Title(x, y, _("Vertical offset")));
266         y += ys30;
267         add_subwindow(v_y = new DownSampleSize(plugin,
268                 x,
269                 y,
270                 &plugin->config.vertical_y,
271                 0,
272                 100));
273         y += ys30;
274         add_subwindow(r = new DownSampleToggle(plugin,
275                 x,
276                 y,
277                 &plugin->config.r,
278                 _("Red")));
279         y += ys30;
280         add_subwindow(g = new DownSampleToggle(plugin,
281                 x,
282                 y,
283                 &plugin->config.g,
284                 _("Green")));
285         y += ys30;
286         add_subwindow(b = new DownSampleToggle(plugin,
287                 x,
288                 y,
289                 &plugin->config.b,
290                 _("Blue")));
291         y += ys30;
292         add_subwindow(a = new DownSampleToggle(plugin,
293                 x,
294                 y,
295                 &plugin->config.a,
296                 _("Alpha")));
297         y += ys30;
298
299         show_window();
300         flush();
301 }
302
303
304
305
306
307
308
309
310
311
312
313 DownSampleToggle::DownSampleToggle(DownSampleMain *plugin,
314         int x,
315         int y,
316         int *output,
317         char *string)
318  : BC_CheckBox(x, y, *output, string)
319 {
320         this->plugin = plugin;
321         this->output = output;
322 }
323
324 int DownSampleToggle::handle_event()
325 {
326         *output = get_value();
327         plugin->send_configure_change();
328         return 1;
329 }
330
331
332
333
334
335
336
337 DownSampleSize::DownSampleSize(DownSampleMain *plugin,
338         int x,
339         int y,
340         int *output,
341         int min,
342         int max)
343  : BC_ISlider(x, y, 0, xS(200), yS(200), min, max, *output)
344 {
345         this->plugin = plugin;
346         this->output = output;
347 }
348 int DownSampleSize::handle_event()
349 {
350         *output = get_value();
351         plugin->send_configure_change();
352         return 1;
353 }
354
355
356
357
358
359
360
361
362
363
364 DownSampleMain::DownSampleMain(PluginServer *server)
365  : PluginVClient(server)
366 {
367
368         engine = 0;
369 }
370
371 DownSampleMain::~DownSampleMain()
372 {
373
374
375         if(engine) delete engine;
376 }
377
378 const char* DownSampleMain::plugin_title() { return N_("Downsample"); }
379 int DownSampleMain::is_realtime() { return 1; }
380
381
382 NEW_WINDOW_MACRO(DownSampleMain, DownSampleWindow)
383
384 LOAD_CONFIGURATION_MACRO(DownSampleMain, DownSampleConfig)
385
386
387 int DownSampleMain::process_buffer(VFrame *frame,
388         int64_t start_position,
389         double frame_rate)
390 {
391         this->input = frame;
392         this->output = frame;
393         load_configuration();
394
395 // This can't be done efficiently in a shader because every output pixel
396 // requires summing a large, arbitrary block of the input pixels.
397 // Scaling down a texture wouldn't average every pixel.
398         read_frame(frame, 0, start_position, frame_rate, 0);
399 //              get_use_opengl());
400
401 // Use hardware
402 //      if(get_use_opengl())
403 //      {
404 //              run_opengl();
405 //              return 0;
406 //      }
407
408 // Process in destination
409         if(!engine) engine = new DownSampleServer(get_project_smp() + 1,
410                 get_project_smp() + 1);
411         engine->process_frame(output, output,
412                 config.r, config.g, config.b, config.a,
413                 config.vertical, config.horizontal,
414                 config.vertical_y, config.horizontal_x);
415
416         return 0;
417 }
418
419
420 void DownSampleMain::update_gui()
421 {
422         if(thread)
423         {
424                 load_configuration();
425                 ((DownSampleWindow*)thread->window)->lock_window();
426                 ((DownSampleWindow*)thread->window)->h->update(config.horizontal);
427                 ((DownSampleWindow*)thread->window)->v->update(config.vertical);
428                 ((DownSampleWindow*)thread->window)->h_x->update(config.horizontal_x);
429                 ((DownSampleWindow*)thread->window)->v_y->update(config.vertical_y);
430                 ((DownSampleWindow*)thread->window)->r->update(config.r);
431                 ((DownSampleWindow*)thread->window)->g->update(config.g);
432                 ((DownSampleWindow*)thread->window)->b->update(config.b);
433                 ((DownSampleWindow*)thread->window)->a->update(config.a);
434                 ((DownSampleWindow*)thread->window)->unlock_window();
435         }
436 }
437
438
439
440
441 void DownSampleMain::save_data(KeyFrame *keyframe)
442 {
443         FileXML output;
444
445 // cause data to be stored directly in text
446         output.set_shared_output(keyframe->xbuf);
447         output.tag.set_title("DOWNSAMPLE");
448
449         output.tag.set_property("HORIZONTAL", config.horizontal);
450         output.tag.set_property("VERTICAL", config.vertical);
451         output.tag.set_property("HORIZONTAL_X", config.horizontal_x);
452         output.tag.set_property("VERTICAL_Y", config.vertical_y);
453         output.tag.set_property("R", config.r);
454         output.tag.set_property("G", config.g);
455         output.tag.set_property("B", config.b);
456         output.tag.set_property("A", config.a);
457         output.append_tag();
458         output.tag.set_title("/DOWNSAMPLE");
459         output.append_tag();
460         output.append_newline();
461         output.terminate_string();
462 }
463
464 void DownSampleMain::read_data(KeyFrame *keyframe)
465 {
466         FileXML input;
467         input.set_shared_input(keyframe->xbuf);
468         int result = 0;
469
470         while(!result) {
471                 result = input.read_tag();
472                 if(!result) {
473                         if(input.tag.title_is("DOWNSAMPLE")) {
474                                 config.horizontal = input.tag.get_property("HORIZONTAL", config.horizontal);
475                                 config.vertical = input.tag.get_property("VERTICAL", config.vertical);
476                                 config.horizontal_x = input.tag.get_property("HORIZONTAL_X", config.horizontal_x);
477                                 config.vertical_y = input.tag.get_property("VERTICAL_Y", config.vertical_y);
478                                 config.r = input.tag.get_property("R", config.r);
479                                 config.g = input.tag.get_property("G", config.g);
480                                 config.b = input.tag.get_property("B", config.b);
481                                 config.a = input.tag.get_property("A", config.a);
482                         }
483                 }
484         }
485 }
486
487
488 int DownSampleMain::handle_opengl()
489 {
490 #ifdef HAVE_GL
491         static const char *downsample_frag =
492                 "uniform sampler2D tex;\n"
493                 "uniform float w;\n"
494                 "uniform float h;\n"
495                 "uniform float x_offset;\n"
496                 "uniform float y_offset;\n";
497         (void) downsample_frag; // whatever
498 #endif
499         return 0;
500 }
501
502