4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
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.
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.
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
22 #include "bcdisplayinfo.h"
28 #include "pluginvclient.h"
30 #include "transportque.h"
35 class ReframeRTWindow;
42 int equivalent(ReframeRTConfig &src);
43 void copy_from(ReframeRTConfig &src);
44 void interpolate(ReframeRTConfig &prev,
45 ReframeRTConfig &next,
48 int64_t current_frame);
56 class ReframeRTScale : public BC_TumbleTextBox
59 ReframeRTScale(ReframeRT *plugin,
67 class ReframeRTStretch : public BC_Radial
70 ReframeRTStretch(ReframeRT *plugin,
79 class ReframeRTDownsample : public BC_Radial
82 ReframeRTDownsample(ReframeRT *plugin,
91 class ReframeRTInterpolate : public BC_CheckBox
94 ReframeRTInterpolate(ReframeRT *plugin,
100 ReframeRTWindow *gui;
103 class ReframeRTWindow : public PluginClientWindow
106 ReframeRTWindow(ReframeRT *plugin);
108 void create_objects();
110 ReframeRTScale *scale;
111 ReframeRTStretch *stretch;
112 ReframeRTDownsample *downsample;
113 ReframeRTInterpolate *interpolate;
117 class ReframeRT : public PluginVClient
120 ReframeRT(PluginServer *server);
123 PLUGIN_CLASS_MEMBERS(ReframeRTConfig)
125 void save_data(KeyFrame *keyframe);
126 void read_data(KeyFrame *keyframe);
130 int process_buffer(VFrame *frame,
131 int64_t start_position,
141 REGISTER_PLUGIN(ReframeRT);
145 ReframeRTConfig::ReframeRTConfig()
153 int ReframeRTConfig::equivalent(ReframeRTConfig &src)
155 return fabs(scale - src.scale) < 0.0001 &&
156 stretch == src.stretch &&
157 interp == src.interp;
160 void ReframeRTConfig::copy_from(ReframeRTConfig &src)
162 this->scale = src.scale;
163 this->stretch = src.stretch;
164 this->interp = src.interp;
167 void ReframeRTConfig::interpolate(ReframeRTConfig &prev,
168 ReframeRTConfig &next,
171 int64_t current_frame)
173 this->interp = prev.interp;
174 this->stretch = prev.stretch;
176 if (this->interp && prev_frame != next_frame)
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;
184 this->scale = prev.scale;
188 void ReframeRTConfig::boundaries()
190 if(fabs(scale) < 0.0001) scale = 0.0001;
200 ReframeRTWindow::ReframeRTWindow(ReframeRT *plugin)
201 : PluginClientWindow(plugin,
208 this->plugin = plugin;
211 ReframeRTWindow::~ReframeRTWindow()
215 void ReframeRTWindow::create_objects()
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,
225 scale->create_objects();
226 scale->set_increment(0.1);
228 add_subwindow(stretch = new ReframeRTStretch(plugin,
233 add_subwindow(downsample = new ReframeRTDownsample(plugin,
238 add_subwindow(interpolate = new ReframeRTInterpolate(plugin,
253 ReframeRTScale::ReframeRTScale(ReframeRT *plugin,
254 ReframeRTWindow *gui,
257 : BC_TumbleTextBox(gui,
258 (float)plugin->config.scale,
265 this->plugin = plugin;
268 int ReframeRTScale::handle_event()
270 plugin->config.scale = atof(get_text());
271 plugin->config.boundaries();
272 plugin->send_configure_change();
276 ReframeRTStretch::ReframeRTStretch(ReframeRT *plugin,
277 ReframeRTWindow *gui,
280 : BC_Radial(x, y, plugin->config.stretch, _("Stretch"))
282 this->plugin = plugin;
286 int ReframeRTStretch::handle_event()
288 plugin->config.stretch = get_value();
289 gui->downsample->update(!get_value());
290 plugin->send_configure_change();
295 ReframeRTDownsample::ReframeRTDownsample(ReframeRT *plugin,
296 ReframeRTWindow *gui,
299 : BC_Radial(x, y, !plugin->config.stretch, _("Downsample"))
301 this->plugin = plugin;
305 int ReframeRTDownsample::handle_event()
307 plugin->config.stretch = !get_value();
308 gui->stretch->update(!get_value());
309 plugin->send_configure_change();
313 ReframeRTInterpolate::ReframeRTInterpolate(ReframeRT *plugin,
314 ReframeRTWindow *gui,
317 : BC_CheckBox(x, y, 0, _("Interpolate"))
319 this->plugin = plugin;
323 int ReframeRTInterpolate::handle_event()
325 plugin->config.interp = get_value();
326 gui->interpolate->update(get_value());
327 plugin->send_configure_change();
331 ReframeRT::ReframeRT(PluginServer *server)
332 : PluginVClient(server)
336 ReframeRT::~ReframeRT()
341 const char* ReframeRT::plugin_title() { return _("ReframeRT"); }
342 int ReframeRT::is_realtime() { return 1; }
343 int ReframeRT::is_synthesis() { return 1; }
346 NEW_WINDOW_MACRO(ReframeRT, ReframeRTWindow)
347 LOAD_CONFIGURATION_MACRO(ReframeRT, ReframeRTConfig)
349 int ReframeRT::process_buffer(VFrame *frame,
350 int64_t start_position,
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;
358 double input_rate = frame_rate;
359 int is_current_keyframe;
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;
369 // calculate input_frame accounting for all previous keyframes
372 tmp_keyframe = next_keyframe;
373 next_keyframe = get_next_keyframe(tmp_keyframe->position+1, 0);
375 tmp_position = edl_to_local(tmp_keyframe->position);
376 next_position = edl_to_local(next_keyframe->position);
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
383 if (is_current_keyframe)
384 segment_len = start_position - tmp_position;
386 segment_len = next_position - tmp_position;
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);
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);
402 input_rate *= config.scale;
404 // printf("ReframeRT::process_buffer %d %lld %f %lld %f\n",
417 delete fake_keyframe;
424 void ReframeRT::save_data(KeyFrame *keyframe)
428 // cause data to be stored directly in text
429 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
430 output.tag.set_title("REFRAMERT");
431 output.tag.set_property("SCALE", config.scale);
432 output.tag.set_property("STRETCH", config.stretch);
433 output.tag.set_property("INTERPOLATE", config.interp);
435 output.terminate_string();
438 void ReframeRT::read_data(KeyFrame *keyframe)
442 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
444 while(!input.read_tag())
446 if(input.tag.title_is("REFRAMERT"))
448 config.scale = input.tag.get_property("SCALE", config.scale);
449 config.stretch = input.tag.get_property("STRETCH", config.stretch);
450 config.interp = input.tag.get_property("INTERPOLATE", config.interp);
455 void ReframeRT::update_gui()
459 int changed = load_configuration();
463 ReframeRTWindow* window = (ReframeRTWindow*)thread->window;
464 window->lock_window("ReframeRT::update_gui");
465 window->scale->update((float)config.scale);
466 window->stretch->update(config.stretch);
467 window->downsample->update(!config.stretch);
468 window->interpolate->update(config.interp);
469 window->unlock_window();