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, 230, 160, 230, 160, 0)
203 this->plugin = plugin;
206 ReframeRTWindow::~ReframeRTWindow()
210 void ReframeRTWindow::create_objects()
214 add_subwindow(title = new BC_Title(x, y, _("Scale by amount:")));
215 y += title->get_h() + plugin->get_theme()->widget_border;
216 scale = new ReframeRTScale(plugin,
220 scale->create_objects();
221 scale->set_increment(0.1);
223 add_subwindow(stretch = new ReframeRTStretch(plugin,
228 add_subwindow(downsample = new ReframeRTDownsample(plugin,
233 add_subwindow(interpolate = new ReframeRTInterpolate(plugin,
248 ReframeRTScale::ReframeRTScale(ReframeRT *plugin,
249 ReframeRTWindow *gui,
252 : BC_TumbleTextBox(gui,
253 (float)plugin->config.scale,
260 this->plugin = plugin;
263 int ReframeRTScale::handle_event()
265 plugin->config.scale = atof(get_text());
266 plugin->config.boundaries();
267 plugin->send_configure_change();
271 ReframeRTStretch::ReframeRTStretch(ReframeRT *plugin,
272 ReframeRTWindow *gui,
275 : BC_Radial(x, y, plugin->config.stretch, _("Stretch"))
277 this->plugin = plugin;
281 int ReframeRTStretch::handle_event()
283 plugin->config.stretch = get_value();
284 gui->downsample->update(!get_value());
285 plugin->send_configure_change();
290 ReframeRTDownsample::ReframeRTDownsample(ReframeRT *plugin,
291 ReframeRTWindow *gui,
294 : BC_Radial(x, y, !plugin->config.stretch, _("Downsample"))
296 this->plugin = plugin;
300 int ReframeRTDownsample::handle_event()
302 plugin->config.stretch = !get_value();
303 gui->stretch->update(!get_value());
304 plugin->send_configure_change();
308 ReframeRTInterpolate::ReframeRTInterpolate(ReframeRT *plugin,
309 ReframeRTWindow *gui,
312 : BC_CheckBox(x, y, 0, _("Interpolate"))
314 this->plugin = plugin;
318 int ReframeRTInterpolate::handle_event()
320 plugin->config.interp = get_value();
321 gui->interpolate->update(get_value());
322 plugin->send_configure_change();
326 ReframeRT::ReframeRT(PluginServer *server)
327 : PluginVClient(server)
331 ReframeRT::~ReframeRT()
336 const char* ReframeRT::plugin_title() { return _("ReframeRT"); }
337 int ReframeRT::is_realtime() { return 1; }
338 int ReframeRT::is_synthesis() { return 1; }
341 NEW_WINDOW_MACRO(ReframeRT, ReframeRTWindow)
342 LOAD_CONFIGURATION_MACRO(ReframeRT, ReframeRTConfig)
344 int ReframeRT::process_buffer(VFrame *frame,
345 int64_t start_position,
348 int64_t input_frame = get_source_start();
349 ReframeRTConfig prev_config, next_config;
350 KeyFrame *tmp_keyframe, *next_keyframe = get_prev_keyframe(get_source_start());
351 int64_t tmp_position, next_position;
353 double input_rate = frame_rate;
354 int is_current_keyframe;
356 // if there are no keyframes, the default keyframe is used, and its position is always 0;
357 // if there are keyframes, the first keyframe can be after the effect start (and it controls settings before it)
358 // so let's calculate using a fake keyframe with the same settings but position == effect start
359 KeyFrame *fake_keyframe = new KeyFrame();
360 fake_keyframe->copy_from(next_keyframe);
361 fake_keyframe->position = local_to_edl(get_source_start());
362 next_keyframe = fake_keyframe;
364 // calculate input_frame accounting for all previous keyframes
367 tmp_keyframe = next_keyframe;
368 next_keyframe = get_next_keyframe(tmp_keyframe->position+1, 0);
370 tmp_position = edl_to_local(tmp_keyframe->position);
371 next_position = edl_to_local(next_keyframe->position);
373 is_current_keyframe =
374 next_position > start_position // the next keyframe is after the current position
375 || next_keyframe->position == tmp_keyframe->position // there are no more keyframes
376 || !next_keyframe->position; // there are no keyframes at all
378 if (is_current_keyframe)
379 segment_len = start_position - tmp_position;
381 segment_len = next_position - tmp_position;
383 read_data(next_keyframe);
384 next_config.copy_from(config);
385 read_data(tmp_keyframe);
386 prev_config.copy_from(config);
387 config.interpolate(prev_config, next_config, tmp_position, next_position, tmp_position + segment_len);
389 // the area under the curve is the number of frames to advance
390 // as long as interpolate() uses a linear slope we can use geometry to determine this
391 // if interpolate() changes to use a curve then this needs use (possibly) the definite integral
392 input_frame += (int64_t)(segment_len * ((prev_config.scale + config.scale) / 2));
393 } while (!is_current_keyframe);
397 input_rate *= config.scale;
399 // printf("ReframeRT::process_buffer %d %lld %f %lld %f\n",
412 delete fake_keyframe;
419 void ReframeRT::save_data(KeyFrame *keyframe)
423 // cause data to be stored directly in text
424 output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
425 output.tag.set_title("REFRAMERT");
426 output.tag.set_property("SCALE", config.scale);
427 output.tag.set_property("STRETCH", config.stretch);
428 output.tag.set_property("INTERPOLATE", config.interp);
430 output.tag.set_title("/REFRAMERT");
432 output.append_newline();
433 output.terminate_string();
436 void ReframeRT::read_data(KeyFrame *keyframe)
440 input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
442 while(!input.read_tag())
444 if(input.tag.title_is("REFRAMERT"))
446 config.scale = input.tag.get_property("SCALE", config.scale);
447 config.stretch = input.tag.get_property("STRETCH", config.stretch);
448 config.interp = input.tag.get_property("INTERPOLATE", config.interp);
453 void ReframeRT::update_gui()
457 int changed = load_configuration();
461 ReframeRTWindow* window = (ReframeRTWindow*)thread->window;
462 window->lock_window("ReframeRT::update_gui");
463 window->scale->update((float)config.scale);
464 window->stretch->update(config.stretch);
465 window->downsample->update(!config.stretch);
466 window->interpolate->update(config.interp);
467 window->unlock_window();