+
+/*
+ * CINELERRA
+ * Copyright (C) 2007 Hermann Vosseler
+ *
+ * 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 "keyframe.h"
+#include "language.h"
+#include "overlayframe.h"
+#include "pluginvclient.h"
+#include "vframe.h"
+
+#include <string.h>
+#include <stdint.h>
+
+
+class Reroute;
+class RerouteWindow;
+
+
+class RerouteConfig
+{
+public:
+ RerouteConfig();
+
+
+
+ static const char* operation_to_text(int operation);
+ int operation;
+ enum
+ {
+ REPLACE,
+ REPLACE_COMPONENTS,
+ REPLACE_ALPHA
+ };
+
+ static const char* output_to_text(int output_track);
+ int output_track;
+ enum
+ {
+ TOP,
+ BOTTOM
+ };
+};
+
+
+
+
+
+
+class RerouteOperation : public BC_PopupMenu
+{
+public:
+ RerouteOperation(Reroute *plugin,
+ int x,
+ int y);
+ void create_objects();
+ int handle_event();
+ Reroute *plugin;
+};
+
+class RerouteOutput : public BC_PopupMenu
+{
+public:
+ RerouteOutput(Reroute *plugin,
+ int x,
+ int y);
+ void create_objects();
+ int handle_event();
+ Reroute *plugin;
+};
+
+
+class RerouteWindow : public PluginClientWindow
+{
+public:
+ RerouteWindow(Reroute *plugin);
+ ~RerouteWindow();
+
+ void create_objects();
+
+ Reroute *plugin;
+ RerouteOperation *operation;
+ RerouteOutput *output;
+};
+
+
+
+
+
+class Reroute : public PluginVClient
+{
+public:
+ Reroute(PluginServer *server);
+ ~Reroute();
+
+
+ PLUGIN_CLASS_MEMBERS(RerouteConfig);
+
+ int process_buffer(VFrame **frame, int64_t start_position, double frame_rate);
+ int is_realtime();
+ int is_multichannel();
+ void save_data(KeyFrame *keyframe);
+ void read_data(KeyFrame *keyframe);
+ void update_gui();
+
+ int output_track;
+ int input_track;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+RerouteConfig::RerouteConfig()
+{
+ operation = RerouteConfig::REPLACE;
+ output_track = RerouteConfig::TOP;
+}
+
+
+const char* RerouteConfig::operation_to_text(int operation)
+{
+ switch(operation)
+ {
+ case RerouteConfig::REPLACE: return _("replace Target");
+ case RerouteConfig::REPLACE_COMPONENTS: return _("Components only");
+ case RerouteConfig::REPLACE_ALPHA: return _("Alpha replace");
+ }
+ return "";
+}
+
+const char* RerouteConfig::output_to_text(int output_track)
+{
+ switch(output_track)
+ {
+ case RerouteConfig::TOP: return _("Top");
+ case RerouteConfig::BOTTOM: return _("Bottom");
+ }
+ return "";
+}
+
+
+
+
+
+
+
+
+
+RerouteWindow::RerouteWindow(Reroute *plugin)
+ : PluginClientWindow(plugin, 300, 160, 0, 0, 1)
+{
+ this->plugin = plugin;
+}
+
+RerouteWindow::~RerouteWindow()
+{
+}
+
+void RerouteWindow::create_objects()
+{
+ int x = 10, y = 10;
+
+ BC_Title *title;
+ add_subwindow(title = new BC_Title(x, y, _("Target track:")));
+
+ int col2 = title->get_w() + 5;
+ add_subwindow(output = new RerouteOutput(plugin,
+ x + col2,
+ y));
+ output->create_objects();
+
+ y += 30;
+ add_subwindow(title = new BC_Title(x, y, _("Operation:")));
+ add_subwindow(operation = new RerouteOperation(plugin,
+ x + col2,
+ y));
+ operation->create_objects();
+
+ show_window();
+ flush();
+}
+
+
+
+
+
+
+
+
+RerouteOperation::RerouteOperation(Reroute *plugin,
+ int x,
+ int y)
+ : BC_PopupMenu(x,
+ y,
+ 150,
+ RerouteConfig::operation_to_text(plugin->config.operation),
+ 1)
+{
+ this->plugin = plugin;
+}
+
+void RerouteOperation::create_objects()
+{
+ add_item(new BC_MenuItem(
+ RerouteConfig::operation_to_text(
+ RerouteConfig::REPLACE)));
+ add_item(new BC_MenuItem(
+ RerouteConfig::operation_to_text(
+ RerouteConfig::REPLACE_COMPONENTS)));
+ add_item(new BC_MenuItem(
+ RerouteConfig::operation_to_text(
+ RerouteConfig::REPLACE_ALPHA)));
+}
+
+int RerouteOperation::handle_event()
+{
+ char *text = get_text();
+
+ if(!strcmp(text,
+ RerouteConfig::operation_to_text(
+ RerouteConfig::REPLACE)))
+ plugin->config.operation = RerouteConfig::REPLACE;
+ else
+ if(!strcmp(text,
+ RerouteConfig::operation_to_text(
+ RerouteConfig::REPLACE_COMPONENTS)))
+ plugin->config.operation = RerouteConfig::REPLACE_COMPONENTS;
+ else
+ if(!strcmp(text,
+ RerouteConfig::operation_to_text(
+ RerouteConfig::REPLACE_ALPHA)))
+ plugin->config.operation = RerouteConfig::REPLACE_ALPHA;
+
+ plugin->send_configure_change();
+ return 1;
+}
+
+
+RerouteOutput::RerouteOutput(Reroute *plugin,
+ int x,
+ int y)
+ : BC_PopupMenu(x,
+ y,
+ 100,
+ RerouteConfig::output_to_text(plugin->config.output_track),
+ 1)
+{
+ this->plugin = plugin;
+}
+
+void RerouteOutput::create_objects()
+{
+ add_item(new BC_MenuItem(
+ RerouteConfig::output_to_text(
+ RerouteConfig::TOP)));
+ add_item(new BC_MenuItem(
+ RerouteConfig::output_to_text(
+ RerouteConfig::BOTTOM)));
+}
+
+int RerouteOutput::handle_event()
+{
+ char *text = get_text();
+
+ if(!strcmp(text,
+ RerouteConfig::output_to_text(
+ RerouteConfig::TOP)))
+ plugin->config.output_track = RerouteConfig::TOP;
+ else
+ if(!strcmp(text,
+ RerouteConfig::output_to_text(
+ RerouteConfig::BOTTOM)))
+ plugin->config.output_track = RerouteConfig::BOTTOM;
+
+ plugin->send_configure_change();
+ return 1;
+}
+
+
+
+
+
+/***** Register Plugin ***********************************/
+
+
+REGISTER_PLUGIN(Reroute)
+
+
+
+
+
+
+
+Reroute::Reroute(PluginServer *server)
+ : PluginVClient(server)
+{
+}
+
+
+Reroute::~Reroute()
+{
+}
+
+
+
+/*
+ * Main operation
+ *
+ *****************************************/
+template<class TYPE, int COMPONENTS>
+struct px_type
+{
+ static inline
+ void transfer(VFrame*, VFrame*, bool, bool) ;
+};
+
+template<class TYPE, int COMPONENTS>
+void px_type<TYPE,COMPONENTS>::transfer(VFrame *source, VFrame *target, bool do_components, bool do_alpha)
+//partially overwrite target data buffer
+{
+ int w = target->get_w();
+ int h = source->get_h();
+ do_alpha = do_alpha && (COMPONENTS > 3); // only possible if we have alpha
+
+ for(int i = 0; i < h; i++)
+ {
+ TYPE *inpx = (TYPE*)source->get_rows()[i];
+ TYPE *outpx = (TYPE*)target->get_rows()[i];
+
+ for(int j = 0; j < w; j++)
+ {
+ if(do_components)
+ {
+ outpx[0] = inpx[0];
+ outpx[1] = inpx[1];
+ outpx[2] = inpx[2];
+ }
+ if(do_alpha)
+ outpx[3] = inpx[3];
+
+ inpx += COMPONENTS;
+ outpx += COMPONENTS;
+ }
+ }
+}
+
+
+
+int Reroute::process_buffer(VFrame **frame,
+ int64_t start_position,
+ double frame_rate)
+{
+ load_configuration();
+
+ bool do_components = true, do_alpha = true;
+ switch(config.operation)
+ {
+ case RerouteConfig::REPLACE: break;
+ case RerouteConfig::REPLACE_ALPHA: do_components = false; break;
+ case RerouteConfig::REPLACE_COMPONENTS: do_alpha = false; break;
+ }
+
+ if(config.output_track == RerouteConfig::TOP)
+ {
+ input_track = get_total_buffers() - 1;
+ output_track = 0;
+ }
+ else
+ {
+ input_track = 0;
+ output_track = get_total_buffers() - 1;
+ }
+
+
+ // output buffers for source and target track
+ VFrame *source = frame[input_track];
+ VFrame *target = frame[output_track];
+
+ // input track always passed through unaltered
+ read_frame(source,
+ input_track,
+ start_position,
+ frame_rate,
+ false ); // no OpenGL support
+
+ // no real operation necessary
+ // unless applied to multiple tracks....
+ if(get_total_buffers() <= 1)
+ return 0;
+
+ if(config.operation == RerouteConfig::REPLACE)
+ {
+ target->copy_from(source);
+ return 0;
+ }
+
+
+ // prepare data for output track
+ // (to be overidden partially)
+ read_frame(target,
+ output_track,
+ start_position,
+ frame_rate,
+ 0);
+
+ switch(source->get_color_model())
+ {
+ case BC_RGB_FLOAT:
+ px_type<float,3>::transfer(source,target, do_components,do_alpha);
+ break;
+ case BC_RGBA_FLOAT:
+ px_type<float,4>::transfer(source,target, do_components,do_alpha);
+ break;
+ case BC_RGB888:
+ case BC_YUV888:
+ px_type<unsigned char,3>::transfer(source,target, do_components,do_alpha);
+ break;
+ case BC_RGBA8888:
+ case BC_YUVA8888:
+ px_type<unsigned char,4>::transfer(source,target, do_components,do_alpha);
+ break;
+ case BC_RGB161616:
+ case BC_YUV161616:
+ px_type<uint16_t,3>::transfer(source,target, do_components,do_alpha);
+ break;
+ case BC_RGBA16161616:
+ case BC_YUVA16161616:
+ px_type<uint16_t,4>::transfer(source,target, do_components,do_alpha);
+ break;
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+const char* Reroute::plugin_title() { return _("Reroute"); }
+int Reroute::is_realtime() { return 1; }
+int Reroute::is_multichannel() { return 1; }
+
+
+
+
+
+NEW_WINDOW_MACRO(Reroute,RerouteWindow)
+
+int Reroute::load_configuration()
+{
+ KeyFrame *prev_keyframe;
+ prev_keyframe = get_prev_keyframe(get_source_position());
+ read_data(prev_keyframe);
+ return 0;
+}
+
+
+void Reroute::save_data(KeyFrame *keyframe)
+{
+ FileXML output;
+
+// write configuration data as XML text
+ output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
+ output.tag.set_title("REROUTE");
+ output.tag.set_property("OPERATION", config.operation);
+ output.tag.set_property("OUTPUT_TRACK", config.output_track);
+ output.append_tag();
+ output.tag.set_title("/REROUTE");
+ output.append_tag();
+ output.terminate_string();
+}
+
+void Reroute::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("REROUTE"))
+ {
+ config.operation = input.tag.get_property("OPERATION", config.operation);
+ config.output_track = input.tag.get_property("OUTPUT_TRACK", config.output_track);
+ }
+ }
+}
+
+void Reroute::update_gui()
+{
+ if(thread)
+ {
+ RerouteWindow *window = (RerouteWindow *)thread->window;
+ window->lock_window("Reroute::update_gui");
+ window->operation->set_text(RerouteConfig::operation_to_text(config.operation));
+ window->output->set_text(RerouteConfig::output_to_text(config.output_track));
+ window->unlock_window();
+ }
+}