4 * Copyright (C) 2008-2016 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"
26 #include "reframert.h"
29 #include "pluginvclient.h"
31 #include "transportque.h"
38 REGISTER_PLUGIN(ReframeRT);
42 ReframeRTConfig::ReframeRTConfig()
47 void ReframeRTConfig::reset()
56 int ReframeRTConfig::equivalent(ReframeRTConfig &src)
58 return fabs(num - src.num) < 0.0001 &&
59 fabs(denom - src.denom) < 0.0001 &&
60 stretch == src.stretch &&
64 void ReframeRTConfig::copy_from(ReframeRTConfig &src)
67 this->denom = src.denom;
68 this->stretch = src.stretch;
69 this->interp = src.interp;
72 void ReframeRTConfig::interpolate(ReframeRTConfig &prev,
73 ReframeRTConfig &next,
76 int64_t current_frame)
78 this->interp = prev.interp;
79 this->stretch = prev.stretch;
80 this->denom = prev.denom;
82 if (this->interp && prev_frame != next_frame)
84 double next_weight = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
85 double prev_weight = (double)(next_frame - current_frame) / (next_frame - prev_frame);
86 double prev_slope = prev.num / prev.denom, next_slope = next.num / next.denom;
87 // for interpolation, this is (for now) a simple linear slope to the next keyframe.
88 double scale = prev_slope * prev_weight + next_slope * next_weight;
89 this->num = this->denom * scale;
97 void ReframeRTConfig::boundaries()
99 if(num < 0.0001) num = 0.0001;
100 if(denom < 0.0001) denom = 0.0001;
110 ReframeRTWindow::ReframeRTWindow(ReframeRT *plugin)
111 : PluginClientWindow(plugin, xS(230), yS(235), xS(230), yS(235), 0)
113 this->plugin = plugin;
116 ReframeRTWindow::~ReframeRTWindow()
120 void ReframeRTWindow::create_objects()
122 int x = plugin->get_theme()->window_border;
123 int y = plugin->get_theme()->window_border;
125 add_subwindow(title = new BC_Title(x, y, _("Input frames:")));
126 y += title->get_h() + plugin->get_theme()->widget_border;
127 num = new ReframeRTNum(plugin,
131 num->create_objects();
132 num->set_increment(1.0);
134 y += num->get_h() + plugin->get_theme()->widget_border;
135 add_subwindow(title = new BC_Title(x, y, _("Output frames:")));
136 y += title->get_h() + plugin->get_theme()->widget_border;
137 denom = new ReframeRTDenom(plugin,
141 denom->create_objects();
142 denom->set_increment(1.0);
145 y += denom->get_h() + plugin->get_theme()->widget_border;
146 add_subwindow(stretch = new ReframeRTStretch(plugin, this, x, y));
148 add_subwindow(downsample = new ReframeRTDownsample(plugin, this, x, y));
150 add_subwindow(interpolate = new ReframeRTInterpolate(plugin, this, x, y));
152 add_subwindow(reset = new ReframeRTReset(plugin, this, x, y));
156 void ReframeRTWindow::update()
158 num->update((float)plugin->config.num);
159 denom->update((float)plugin->config.denom);
160 stretch->update(plugin->config.stretch);
161 downsample->update(!plugin->config.stretch);
162 interpolate->update(plugin->config.interp);
170 ReframeRTNum::ReframeRTNum(ReframeRT *plugin,
171 ReframeRTWindow *gui,
174 : BC_TumbleTextBox(gui,
175 (float)plugin->config.num,
180 gui->get_w() - plugin->get_theme()->window_border * 3)
182 this->plugin = plugin;
185 int ReframeRTNum::handle_event()
187 plugin->config.num = atof(get_text());
188 plugin->config.boundaries();
189 plugin->send_configure_change();
194 ReframeRTDenom::ReframeRTDenom(ReframeRT *plugin,
195 ReframeRTWindow *gui,
198 : BC_TumbleTextBox(gui,
199 (float)plugin->config.denom,
204 gui->get_w() - plugin->get_theme()->window_border * 3)
206 this->plugin = plugin;
209 int ReframeRTDenom::handle_event()
211 plugin->config.denom = atof(get_text());
212 plugin->config.boundaries();
213 plugin->send_configure_change();
218 ReframeRTStretch::ReframeRTStretch(ReframeRT *plugin,
219 ReframeRTWindow *gui,
222 : BC_Radial(x, y, plugin->config.stretch, _("Stretch"))
224 this->plugin = plugin;
228 int ReframeRTStretch::handle_event()
230 plugin->config.stretch = get_value();
231 gui->downsample->update(!get_value());
232 plugin->send_configure_change();
237 ReframeRTDownsample::ReframeRTDownsample(ReframeRT *plugin,
238 ReframeRTWindow *gui,
241 : BC_Radial(x, y, !plugin->config.stretch, _("Downsample"))
243 this->plugin = plugin;
247 int ReframeRTDownsample::handle_event()
249 plugin->config.stretch = !get_value();
250 gui->stretch->update(!get_value());
251 plugin->send_configure_change();
255 ReframeRTInterpolate::ReframeRTInterpolate(ReframeRT *plugin,
256 ReframeRTWindow *gui,
259 : BC_CheckBox(x, y, 0, _("Interpolate"))
261 this->plugin = plugin;
265 int ReframeRTInterpolate::handle_event()
267 plugin->config.interp = get_value();
268 gui->interpolate->update(get_value());
269 plugin->send_configure_change();
274 ReframeRTReset::ReframeRTReset(ReframeRT *plugin, ReframeRTWindow *gui, int x, int y)
275 : BC_GenericButton(x, y, _("Reset"))
277 this->plugin = plugin;
280 ReframeRTReset::~ReframeRTReset()
283 int ReframeRTReset::handle_event()
285 plugin->config.reset();
287 plugin->send_configure_change();
293 ReframeRT::ReframeRT(PluginServer *server)
294 : PluginVClient(server)
298 ReframeRT::~ReframeRT()
303 const char* ReframeRT::plugin_title() { return N_("ReframeRT"); }
304 int ReframeRT::is_realtime() { return 1; }
305 int ReframeRT::is_synthesis() { return 1; }
308 NEW_WINDOW_MACRO(ReframeRT, ReframeRTWindow)
309 LOAD_CONFIGURATION_MACRO(ReframeRT, ReframeRTConfig)
311 int ReframeRT::process_buffer(VFrame *frame,
312 int64_t start_position,
315 int64_t input_frame = get_source_start();
316 ReframeRTConfig prev_config, next_config;
317 KeyFrame *tmp_keyframe, *next_keyframe = get_prev_keyframe(get_source_start());
318 int64_t tmp_position, next_position;
320 double input_rate = frame_rate;
321 int is_current_keyframe;
323 // if there are no keyframes, the default keyframe is used, and its position is always 0;
324 // if there are keyframes, the first keyframe can be after the effect start (and it controls settings before it)
325 // so let's calculate using a fake keyframe with the same settings but position == effect start
326 KeyFrame *fake_keyframe = new KeyFrame();
327 fake_keyframe->copy_from(next_keyframe);
328 fake_keyframe->position = local_to_edl(get_source_start());
329 next_keyframe = fake_keyframe;
331 // calculate input_frame accounting for all previous keyframes
334 tmp_keyframe = next_keyframe;
335 next_keyframe = get_next_keyframe(tmp_keyframe->position+1, 0);
337 tmp_position = edl_to_local(tmp_keyframe->position);
338 next_position = edl_to_local(next_keyframe->position);
340 is_current_keyframe =
341 next_position > start_position // the next keyframe is after the current position
342 || next_keyframe->position == tmp_keyframe->position // there are no more keyframes
343 || !next_keyframe->position; // there are no keyframes at all
345 if (is_current_keyframe)
346 segment_len = start_position - tmp_position;
348 segment_len = next_position - tmp_position;
350 read_data(next_keyframe);
351 next_config.copy_from(config);
352 read_data(tmp_keyframe);
353 prev_config.copy_from(config);
354 config.interpolate(prev_config, next_config, tmp_position, next_position, tmp_position + segment_len);
356 // the area under the curve is the number of frames to advance
357 // as long as interpolate() uses a linear slope we can use geometry to determine this
358 // if interpolate() changes to use a curve then this needs use (possibly) the definite integral
359 double prev_scale = prev_config.num / prev_config.denom;
360 double config_scale = config.num / config.denom;
361 input_frame += (int64_t)(segment_len * ((prev_scale + config_scale) / 2));
362 } while (!is_current_keyframe);
367 input_rate *= config.num / config.denom;
371 // printf("ReframeRT::process_buffer %d %lld %f %lld %f\n",
384 delete fake_keyframe;
391 void ReframeRT::save_data(KeyFrame *keyframe)
395 // cause data to be stored directly in text
396 output.set_shared_output(keyframe->xbuf);
397 output.tag.set_title("REFRAMERT");
398 // for backwards compatability, we call num scale
399 output.tag.set_property("SCALE", config.num);
400 output.tag.set_property("DENOM", config.denom);
401 output.tag.set_property("STRETCH", config.stretch);
402 output.tag.set_property("INTERPOLATE", config.interp);
404 output.tag.set_title("/REFRAMERT");
406 output.append_newline();
407 output.terminate_string();
410 void ReframeRT::read_data(KeyFrame *keyframe)
414 input.set_shared_input(keyframe->xbuf);
416 while(!input.read_tag())
418 if(input.tag.title_is("REFRAMERT"))
420 // for backwards compatability, we call num scale
421 config.num = input.tag.get_property("SCALE", config.num);
422 config.denom = input.tag.get_property("DENOM", config.denom);
423 config.stretch = input.tag.get_property("STRETCH", config.stretch);
424 config.interp = input.tag.get_property("INTERPOLATE", config.interp);
429 void ReframeRT::update_gui()
433 int changed = load_configuration();
437 ReframeRTWindow* window = (ReframeRTWindow*)thread->window;
438 window->lock_window("ReframeRT::update_gui");
439 window->num->update((float)config.num);
440 window->denom->update((float)config.denom);
441 window->stretch->update(config.stretch);
442 window->downsample->update(!config.stretch);
443 window->interpolate->update(config.interp);
444 window->unlock_window();