/* * 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 #include 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 struct px_type { static inline void transfer(VFrame*, VFrame*, bool, bool) ; }; template void px_type::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::transfer(source,target, do_components,do_alpha); break; case BC_RGBA_FLOAT: px_type::transfer(source,target, do_components,do_alpha); break; case BC_RGB888: case BC_YUV888: px_type::transfer(source,target, do_components,do_alpha); break; case BC_RGBA8888: case BC_YUVA8888: px_type::transfer(source,target, do_components,do_alpha); break; case BC_RGB161616: case BC_YUV161616: px_type::transfer(source,target, do_components,do_alpha); break; case BC_RGBA16161616: case BC_YUVA16161616: px_type::transfer(source,target, do_components,do_alpha); break; } return 0; } const char* Reroute::plugin_title() { return N_("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->xbuf); 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->xbuf); 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(); } }