update internationalization data
[goodguy/history.git] / cinelerra-5.0 / plugins / reframert / reframert.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 "bcdisplayinfo.h"
23 #include "clip.h"
24 #include "bchash.h"
25 #include "filexml.h"
26 #include "guicast.h"
27 #include "language.h"
28 #include "pluginvclient.h"
29 #include "theme.h"
30 #include "transportque.h"
31
32 #include <string.h>
33
34 class ReframeRT;
35 class ReframeRTWindow;
36
37 class ReframeRTConfig
38 {
39 public:
40         ReframeRTConfig();
41         void boundaries();
42         int equivalent(ReframeRTConfig &src);
43         void copy_from(ReframeRTConfig &src);
44         void interpolate(ReframeRTConfig &prev,
45                 ReframeRTConfig &next,
46                 int64_t prev_frame,
47                 int64_t next_frame,
48                 int64_t current_frame);
49         double scale;
50         int stretch;
51         int interp;
52         int optic_flow;
53 };
54
55
56 class ReframeRTScale : public BC_TumbleTextBox
57 {
58 public:
59         ReframeRTScale(ReframeRT *plugin,
60                 ReframeRTWindow *gui,
61                 int x,
62                 int y);
63         int handle_event();
64         ReframeRT *plugin;
65 };
66
67 class ReframeRTStretch : public BC_Radial
68 {
69 public:
70         ReframeRTStretch(ReframeRT *plugin,
71                 ReframeRTWindow *gui,
72                 int x,
73                 int y);
74         int handle_event();
75         ReframeRT *plugin;
76         ReframeRTWindow *gui;
77 };
78
79 class ReframeRTDownsample : public BC_Radial
80 {
81 public:
82         ReframeRTDownsample(ReframeRT *plugin,
83                 ReframeRTWindow *gui,
84                 int x,
85                 int y);
86         int handle_event();
87         ReframeRT *plugin;
88         ReframeRTWindow *gui;
89 };
90
91 class ReframeRTInterpolate : public BC_CheckBox
92 {
93 public:
94         ReframeRTInterpolate(ReframeRT *plugin,
95                 ReframeRTWindow *gui,
96                 int x,
97                 int y);
98         int handle_event();
99         ReframeRT *plugin;
100         ReframeRTWindow *gui;
101 };
102
103 class ReframeRTWindow : public PluginClientWindow
104 {
105 public:
106         ReframeRTWindow(ReframeRT *plugin);
107         ~ReframeRTWindow();
108         void create_objects();
109         ReframeRT *plugin;
110         ReframeRTScale *scale;
111         ReframeRTStretch *stretch;
112         ReframeRTDownsample *downsample;
113         ReframeRTInterpolate *interpolate;
114 };
115
116
117 class ReframeRT : public PluginVClient
118 {
119 public:
120         ReframeRT(PluginServer *server);
121         ~ReframeRT();
122
123         PLUGIN_CLASS_MEMBERS(ReframeRTConfig)
124
125         void save_data(KeyFrame *keyframe);
126         void read_data(KeyFrame *keyframe);
127         void update_gui();
128         int is_realtime();
129         int is_synthesis();
130         int process_buffer(VFrame *frame,
131                 int64_t start_position,
132                 double frame_rate);
133 };
134
135
136
137
138
139
140
141 REGISTER_PLUGIN(ReframeRT);
142
143
144
145 ReframeRTConfig::ReframeRTConfig()
146 {
147         scale = 1.0;
148         stretch = 0;
149         interp = 0;
150         optic_flow = 1;
151 }
152
153 int ReframeRTConfig::equivalent(ReframeRTConfig &src)
154 {
155         return fabs(scale - src.scale) < 0.0001 &&
156                 stretch == src.stretch &&
157                 interp == src.interp;
158 }
159
160 void ReframeRTConfig::copy_from(ReframeRTConfig &src)
161 {
162         this->scale = src.scale;
163         this->stretch = src.stretch;
164         this->interp = src.interp;
165 }
166
167 void ReframeRTConfig::interpolate(ReframeRTConfig &prev,
168         ReframeRTConfig &next,
169         int64_t prev_frame,
170         int64_t next_frame,
171         int64_t current_frame)
172 {
173         this->interp = prev.interp;
174         this->stretch = prev.stretch;
175
176         if (this->interp && prev_frame != next_frame)
177         {
178                 // for interpolation, this is (for now) a simple linear slope to the next keyframe.
179                 double slope = (next.scale - prev.scale) / (next_frame - prev_frame);
180                 this->scale = (slope * (current_frame - prev_frame)) + prev.scale;
181         }
182         else
183         {
184                 this->scale = prev.scale;
185         }
186 }
187
188 void ReframeRTConfig::boundaries()
189 {
190         if(fabs(scale) < 0.0001) scale = 0.0001;
191 }
192
193
194
195
196
197
198
199
200 ReframeRTWindow::ReframeRTWindow(ReframeRT *plugin)
201  : PluginClientWindow(plugin,
202         210,
203         160,
204         200,
205         160,
206         0)
207 {
208         this->plugin = plugin;
209 }
210
211 ReframeRTWindow::~ReframeRTWindow()
212 {
213 }
214
215 void ReframeRTWindow::create_objects()
216 {
217         int x = 10, y = 10;
218         BC_Title *title;
219         add_subwindow(title = new BC_Title(x, y, _("Scale by amount:")));
220         y += title->get_h() + plugin->get_theme()->widget_border;
221         scale = new ReframeRTScale(plugin,
222                 this,
223                 x,
224                 y);
225         scale->create_objects();
226         scale->set_increment(0.1);
227         y += 30;
228         add_subwindow(stretch = new ReframeRTStretch(plugin,
229                 this,
230                 x,
231                 y));
232         y += 30;
233         add_subwindow(downsample = new ReframeRTDownsample(plugin,
234                 this,
235                 x,
236                 y));
237         y += 30;
238         add_subwindow(interpolate = new ReframeRTInterpolate(plugin,
239                 this,
240                 x,
241                 y));
242         show_window();
243         flush();
244 }
245
246
247
248
249
250
251
252
253 ReframeRTScale::ReframeRTScale(ReframeRT *plugin,
254         ReframeRTWindow *gui,
255         int x,
256         int y)
257  : BC_TumbleTextBox(gui,
258         (float)plugin->config.scale,
259         (float)-1000,
260         (float)1000,
261         x,
262         y,
263         100)
264 {
265         this->plugin = plugin;
266 }
267
268 int ReframeRTScale::handle_event()
269 {
270         plugin->config.scale = atof(get_text());
271         plugin->config.boundaries();
272         plugin->send_configure_change();
273         return 1;
274 }
275
276 ReframeRTStretch::ReframeRTStretch(ReframeRT *plugin,
277         ReframeRTWindow *gui,
278         int x,
279         int y)
280  : BC_Radial(x, y, plugin->config.stretch, _("Stretch"))
281 {
282         this->plugin = plugin;
283         this->gui = gui;
284 }
285
286 int ReframeRTStretch::handle_event()
287 {
288         plugin->config.stretch = get_value();
289         gui->downsample->update(!get_value());
290         plugin->send_configure_change();
291         return 1;
292 }
293
294
295 ReframeRTDownsample::ReframeRTDownsample(ReframeRT *plugin,
296         ReframeRTWindow *gui,
297         int x,
298         int y)
299  : BC_Radial(x, y, !plugin->config.stretch, _("Downsample"))
300 {
301         this->plugin = plugin;
302         this->gui = gui;
303 }
304
305 int ReframeRTDownsample::handle_event()
306 {
307         plugin->config.stretch = !get_value();
308         gui->stretch->update(!get_value());
309         plugin->send_configure_change();
310         return 1;
311 }
312
313 ReframeRTInterpolate::ReframeRTInterpolate(ReframeRT *plugin,
314         ReframeRTWindow *gui,
315         int x,
316         int y)
317  : BC_CheckBox(x, y, 0, _("Interpolate"))
318 {
319         this->plugin = plugin;
320         this->gui = gui;
321 }
322
323 int ReframeRTInterpolate::handle_event()
324 {
325         plugin->config.interp = get_value();
326         gui->interpolate->update(get_value());
327         plugin->send_configure_change();
328         return 1;
329 }
330
331 ReframeRT::ReframeRT(PluginServer *server)
332  : PluginVClient(server)
333 {
334 }
335
336 ReframeRT::~ReframeRT()
337 {
338
339 }
340
341 const char* ReframeRT::plugin_title() { return _("ReframeRT"); }
342 int ReframeRT::is_realtime() { return 1; }
343 int ReframeRT::is_synthesis() { return 1; }
344
345
346 NEW_WINDOW_MACRO(ReframeRT, ReframeRTWindow)
347 LOAD_CONFIGURATION_MACRO(ReframeRT, ReframeRTConfig)
348
349 int ReframeRT::process_buffer(VFrame *frame,
350                 int64_t start_position,
351                 double frame_rate)
352 {
353         int64_t input_frame = get_source_start();
354         ReframeRTConfig prev_config, next_config;
355         KeyFrame *tmp_keyframe, *next_keyframe = get_prev_keyframe(get_source_start());
356         int64_t tmp_position, next_position;
357         int64_t segment_len;
358         double input_rate = frame_rate;
359         int is_current_keyframe;
360
361 // if there are no keyframes, the default keyframe is used, and its position is always 0;
362 // if there are keyframes, the first keyframe can be after the effect start (and it controls settings before it)
363 // so let's calculate using a fake keyframe with the same settings but position == effect start
364         KeyFrame *fake_keyframe = new KeyFrame();
365         fake_keyframe->copy_from(next_keyframe);
366         fake_keyframe->position = local_to_edl(get_source_start());
367         next_keyframe = fake_keyframe;
368
369         // calculate input_frame accounting for all previous keyframes
370         do
371         {
372                 tmp_keyframe = next_keyframe;
373                 next_keyframe = get_next_keyframe(tmp_keyframe->position+1, 0);
374
375                 tmp_position = edl_to_local(tmp_keyframe->position);
376                 next_position = edl_to_local(next_keyframe->position);
377
378                 is_current_keyframe =
379                         next_position > start_position // the next keyframe is after the current position
380                         || next_keyframe->position == tmp_keyframe->position // there are no more keyframes
381                         || !next_keyframe->position; // there are no keyframes at all
382
383                 if (is_current_keyframe)
384                         segment_len = start_position - tmp_position;
385                 else
386                         segment_len = next_position - tmp_position;
387
388                 read_data(next_keyframe);
389                 next_config.copy_from(config);
390                 read_data(tmp_keyframe);
391                 prev_config.copy_from(config);
392                 config.interpolate(prev_config, next_config, tmp_position, next_position, tmp_position + segment_len);
393
394                 // the area under the curve is the number of frames to advance
395                 // as long as interpolate() uses a linear slope we can use geometry to determine this
396                 // if interpolate() changes to use a curve then this needs use (possibly) the definite integral
397                 input_frame += (int64_t)(segment_len * ((prev_config.scale + config.scale) / 2));
398         } while (!is_current_keyframe);
399
400 // Change rate
401         if (!config.stretch)
402                 input_rate *= config.scale;
403
404 // printf("ReframeRT::process_buffer %d %lld %f %lld %f\n",
405 // __LINE__,
406 // start_position,
407 // frame_rate,
408 // input_frame,
409 // input_rate);
410
411         read_frame(frame,
412                 0,
413                 input_frame,
414                 input_rate);
415
416         delete fake_keyframe;
417
418         return 0;
419 }
420
421
422
423 void ReframeRT::save_data(KeyFrame *keyframe)
424 {
425         FileXML output;
426
427 // cause data to be stored directly in text
428         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
429         output.tag.set_title("REFRAMERT");
430         output.tag.set_property("SCALE", config.scale);
431         output.tag.set_property("STRETCH", config.stretch);
432         output.tag.set_property("INTERPOLATE", config.interp);
433         output.append_tag();
434         output.terminate_string();
435 }
436
437 void ReframeRT::read_data(KeyFrame *keyframe)
438 {
439         FileXML input;
440
441         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
442
443         while(!input.read_tag())
444         {
445                 if(input.tag.title_is("REFRAMERT"))
446                 {
447                         config.scale = input.tag.get_property("SCALE", config.scale);
448                         config.stretch = input.tag.get_property("STRETCH", config.stretch);
449                         config.interp = input.tag.get_property("INTERPOLATE", config.interp);
450                 }
451         }
452 }
453
454 void ReframeRT::update_gui()
455 {
456         if(thread)
457         {
458                 int changed = load_configuration();
459
460                 if(changed)
461                 {
462                         ReframeRTWindow* window = (ReframeRTWindow*)thread->window;
463                         window->lock_window("ReframeRT::update_gui");
464                         window->scale->update((float)config.scale);
465                         window->stretch->update(config.stretch);
466                         window->downsample->update(!config.stretch);
467                         window->interpolate->update(config.interp);
468                         window->unlock_window();
469                 }
470         }
471 }
472
473
474
475
476