+++ /dev/null
-
-/*
- * CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include "bcdisplayinfo.h"
-#include "clip.h"
-#include "bchash.h"
-#include "filexml.h"
-#include "guicast.h"
-#include "language.h"
-#include "pluginvclient.h"
-#include "theme.h"
-#include "transportque.h"
-
-#include <string.h>
-
-class ReframeRT;
-class ReframeRTWindow;
-
-class ReframeRTConfig
-{
-public:
- ReframeRTConfig();
- void boundaries();
- int equivalent(ReframeRTConfig &src);
- void copy_from(ReframeRTConfig &src);
- void interpolate(ReframeRTConfig &prev,
- ReframeRTConfig &next,
- int64_t prev_frame,
- int64_t next_frame,
- int64_t current_frame);
- double scale;
- int stretch;
- int interp;
- int optic_flow;
-};
-
-
-class ReframeRTScale : public BC_TumbleTextBox
-{
-public:
- ReframeRTScale(ReframeRT *plugin,
- ReframeRTWindow *gui,
- int x,
- int y);
- int handle_event();
- ReframeRT *plugin;
-};
-
-class ReframeRTStretch : public BC_Radial
-{
-public:
- ReframeRTStretch(ReframeRT *plugin,
- ReframeRTWindow *gui,
- int x,
- int y);
- int handle_event();
- ReframeRT *plugin;
- ReframeRTWindow *gui;
-};
-
-class ReframeRTDownsample : public BC_Radial
-{
-public:
- ReframeRTDownsample(ReframeRT *plugin,
- ReframeRTWindow *gui,
- int x,
- int y);
- int handle_event();
- ReframeRT *plugin;
- ReframeRTWindow *gui;
-};
-
-class ReframeRTInterpolate : public BC_CheckBox
-{
-public:
- ReframeRTInterpolate(ReframeRT *plugin,
- ReframeRTWindow *gui,
- int x,
- int y);
- int handle_event();
- ReframeRT *plugin;
- ReframeRTWindow *gui;
-};
-
-class ReframeRTWindow : public PluginClientWindow
-{
-public:
- ReframeRTWindow(ReframeRT *plugin);
- ~ReframeRTWindow();
- void create_objects();
- ReframeRT *plugin;
- ReframeRTScale *scale;
- ReframeRTStretch *stretch;
- ReframeRTDownsample *downsample;
- ReframeRTInterpolate *interpolate;
-};
-
-
-class ReframeRT : public PluginVClient
-{
-public:
- ReframeRT(PluginServer *server);
- ~ReframeRT();
-
- PLUGIN_CLASS_MEMBERS(ReframeRTConfig)
-
- void save_data(KeyFrame *keyframe);
- void read_data(KeyFrame *keyframe);
- void update_gui();
- int is_realtime();
- int is_synthesis();
- int process_buffer(VFrame *frame,
- int64_t start_position,
- double frame_rate);
-};
-
-
-
-
-
-
-
-REGISTER_PLUGIN(ReframeRT);
-
-
-
-ReframeRTConfig::ReframeRTConfig()
-{
- scale = 1.0;
- stretch = 0;
- interp = 0;
- optic_flow = 1;
-}
-
-int ReframeRTConfig::equivalent(ReframeRTConfig &src)
-{
- return fabs(scale - src.scale) < 0.0001 &&
- stretch == src.stretch &&
- interp == src.interp;
-}
-
-void ReframeRTConfig::copy_from(ReframeRTConfig &src)
-{
- this->scale = src.scale;
- this->stretch = src.stretch;
- this->interp = src.interp;
-}
-
-void ReframeRTConfig::interpolate(ReframeRTConfig &prev,
- ReframeRTConfig &next,
- int64_t prev_frame,
- int64_t next_frame,
- int64_t current_frame)
-{
- this->interp = prev.interp;
- this->stretch = prev.stretch;
-
- if (this->interp && prev_frame != next_frame)
- {
- // for interpolation, this is (for now) a simple linear slope to the next keyframe.
- double slope = (next.scale - prev.scale) / (next_frame - prev_frame);
- this->scale = (slope * (current_frame - prev_frame)) + prev.scale;
- }
- else
- {
- this->scale = prev.scale;
- }
-}
-
-void ReframeRTConfig::boundaries()
-{
- if(fabs(scale) < 0.0001) scale = 0.0001;
-}
-
-
-
-
-
-
-
-
-ReframeRTWindow::ReframeRTWindow(ReframeRT *plugin)
- : PluginClientWindow(plugin,
- 210,
- 160,
- 200,
- 160,
- 0)
-{
- this->plugin = plugin;
-}
-
-ReframeRTWindow::~ReframeRTWindow()
-{
-}
-
-void ReframeRTWindow::create_objects()
-{
- int x = 10, y = 10;
- BC_Title *title;
- add_subwindow(title = new BC_Title(x, y, _("Scale by amount:")));
- y += title->get_h() + plugin->get_theme()->widget_border;
- scale = new ReframeRTScale(plugin,
- this,
- x,
- y);
- scale->create_objects();
- scale->set_increment(0.1);
- y += 30;
- add_subwindow(stretch = new ReframeRTStretch(plugin,
- this,
- x,
- y));
- y += 30;
- add_subwindow(downsample = new ReframeRTDownsample(plugin,
- this,
- x,
- y));
- y += 30;
- add_subwindow(interpolate = new ReframeRTInterpolate(plugin,
- this,
- x,
- y));
- show_window();
- flush();
-}
-
-
-
-
-
-
-
-
-ReframeRTScale::ReframeRTScale(ReframeRT *plugin,
- ReframeRTWindow *gui,
- int x,
- int y)
- : BC_TumbleTextBox(gui,
- (float)plugin->config.scale,
- (float)-1000,
- (float)1000,
- x,
- y,
- 100)
-{
- this->plugin = plugin;
-}
-
-int ReframeRTScale::handle_event()
-{
- plugin->config.scale = atof(get_text());
- plugin->config.boundaries();
- plugin->send_configure_change();
- return 1;
-}
-
-ReframeRTStretch::ReframeRTStretch(ReframeRT *plugin,
- ReframeRTWindow *gui,
- int x,
- int y)
- : BC_Radial(x, y, plugin->config.stretch, _("Stretch"))
-{
- this->plugin = plugin;
- this->gui = gui;
-}
-
-int ReframeRTStretch::handle_event()
-{
- plugin->config.stretch = get_value();
- gui->downsample->update(!get_value());
- plugin->send_configure_change();
- return 1;
-}
-
-
-ReframeRTDownsample::ReframeRTDownsample(ReframeRT *plugin,
- ReframeRTWindow *gui,
- int x,
- int y)
- : BC_Radial(x, y, !plugin->config.stretch, _("Downsample"))
-{
- this->plugin = plugin;
- this->gui = gui;
-}
-
-int ReframeRTDownsample::handle_event()
-{
- plugin->config.stretch = !get_value();
- gui->stretch->update(!get_value());
- plugin->send_configure_change();
- return 1;
-}
-
-ReframeRTInterpolate::ReframeRTInterpolate(ReframeRT *plugin,
- ReframeRTWindow *gui,
- int x,
- int y)
- : BC_CheckBox(x, y, 0, _("Interpolate"))
-{
- this->plugin = plugin;
- this->gui = gui;
-}
-
-int ReframeRTInterpolate::handle_event()
-{
- plugin->config.interp = get_value();
- gui->interpolate->update(get_value());
- plugin->send_configure_change();
- return 1;
-}
-
-ReframeRT::ReframeRT(PluginServer *server)
- : PluginVClient(server)
-{
-}
-
-ReframeRT::~ReframeRT()
-{
-
-}
-
-const char* ReframeRT::plugin_title() { return _("ReframeRT"); }
-int ReframeRT::is_realtime() { return 1; }
-int ReframeRT::is_synthesis() { return 1; }
-
-
-NEW_WINDOW_MACRO(ReframeRT, ReframeRTWindow)
-LOAD_CONFIGURATION_MACRO(ReframeRT, ReframeRTConfig)
-
-int ReframeRT::process_buffer(VFrame *frame,
- int64_t start_position,
- double frame_rate)
-{
- int64_t input_frame = get_source_start();
- ReframeRTConfig prev_config, next_config;
- KeyFrame *tmp_keyframe, *next_keyframe = get_prev_keyframe(get_source_start());
- int64_t tmp_position, next_position;
- int64_t segment_len;
- double input_rate = frame_rate;
- int is_current_keyframe;
-
-// if there are no keyframes, the default keyframe is used, and its position is always 0;
-// if there are keyframes, the first keyframe can be after the effect start (and it controls settings before it)
-// so let's calculate using a fake keyframe with the same settings but position == effect start
- KeyFrame *fake_keyframe = new KeyFrame();
- fake_keyframe->copy_from(next_keyframe);
- fake_keyframe->position = local_to_edl(get_source_start());
- next_keyframe = fake_keyframe;
-
- // calculate input_frame accounting for all previous keyframes
- do
- {
- tmp_keyframe = next_keyframe;
- next_keyframe = get_next_keyframe(tmp_keyframe->position+1, 0);
-
- tmp_position = edl_to_local(tmp_keyframe->position);
- next_position = edl_to_local(next_keyframe->position);
-
- is_current_keyframe =
- next_position > start_position // the next keyframe is after the current position
- || next_keyframe->position == tmp_keyframe->position // there are no more keyframes
- || !next_keyframe->position; // there are no keyframes at all
-
- if (is_current_keyframe)
- segment_len = start_position - tmp_position;
- else
- segment_len = next_position - tmp_position;
-
- read_data(next_keyframe);
- next_config.copy_from(config);
- read_data(tmp_keyframe);
- prev_config.copy_from(config);
- config.interpolate(prev_config, next_config, tmp_position, next_position, tmp_position + segment_len);
-
- // the area under the curve is the number of frames to advance
- // as long as interpolate() uses a linear slope we can use geometry to determine this
- // if interpolate() changes to use a curve then this needs use (possibly) the definite integral
- input_frame += (int64_t)(segment_len * ((prev_config.scale + config.scale) / 2));
- } while (!is_current_keyframe);
-
-// Change rate
- if (!config.stretch)
- input_rate *= config.scale;
-
-// printf("ReframeRT::process_buffer %d %lld %f %lld %f\n",
-// __LINE__,
-// start_position,
-// frame_rate,
-// input_frame,
-// input_rate);
-
- read_frame(frame,
- 0,
- input_frame,
- input_rate,
- 0);
-
- delete fake_keyframe;
-
- return 0;
-}
-
-
-
-void ReframeRT::save_data(KeyFrame *keyframe)
-{
- FileXML output;
-
-// cause data to be stored directly in text
- output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
- output.tag.set_title("REFRAMERT");
- output.tag.set_property("SCALE", config.scale);
- output.tag.set_property("STRETCH", config.stretch);
- output.tag.set_property("INTERPOLATE", config.interp);
- output.append_tag();
- output.tag.set_title("/REFRAMERT");
- output.append_tag();
- output.append_newline();
- output.terminate_string();
-}
-
-void ReframeRT::read_data(KeyFrame *keyframe)
-{
- FileXML input;
-
- input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
-
- while(!input.read_tag())
- {
- if(input.tag.title_is("REFRAMERT"))
- {
- config.scale = input.tag.get_property("SCALE", config.scale);
- config.stretch = input.tag.get_property("STRETCH", config.stretch);
- config.interp = input.tag.get_property("INTERPOLATE", config.interp);
- }
- }
-}
-
-void ReframeRT::update_gui()
-{
- if(thread)
- {
- int changed = load_configuration();
-
- if(changed)
- {
- ReframeRTWindow* window = (ReframeRTWindow*)thread->window;
- window->lock_window("ReframeRT::update_gui");
- window->scale->update((float)config.scale);
- window->stretch->update(config.stretch);
- window->downsample->update(!config.stretch);
- window->interpolate->update(config.interp);
- window->unlock_window();
- }
- }
-}
-
-
-
-
-