Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / plugins / freezeframe / freezeframe.C
diff --git a/cinelerra-5.1/plugins/freezeframe/freezeframe.C b/cinelerra-5.1/plugins/freezeframe/freezeframe.C
new file mode 100644 (file)
index 0000000..6938575
--- /dev/null
@@ -0,0 +1,350 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2012 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 "bchash.h"
+#include "filexml.h"
+#include "freezeframe.h"
+#include "language.h"
+#include "transportque.inc"
+
+
+
+#include <string.h>
+
+
+REGISTER_PLUGIN(FreezeFrameMain)
+
+
+
+
+
+FreezeFrameConfig::FreezeFrameConfig()
+{
+       enabled = 0;
+       line_double = 0;
+}
+
+void FreezeFrameConfig::copy_from(FreezeFrameConfig &that)
+{
+       enabled = that.enabled;
+       line_double = that.line_double;
+}
+
+int FreezeFrameConfig::equivalent(FreezeFrameConfig &that)
+{
+       return enabled == that.enabled &&
+               line_double == that.line_double;
+}
+
+void FreezeFrameConfig::interpolate(FreezeFrameConfig &prev, 
+       FreezeFrameConfig &next, 
+       long prev_frame, 
+       long next_frame, 
+       long current_frame)
+{
+       this->enabled = prev.enabled;
+       this->line_double = prev.line_double;
+}
+
+
+
+
+
+
+
+
+
+
+FreezeFrameWindow::FreezeFrameWindow(FreezeFrameMain *client)
+ : PluginClientWindow(client,
+       200,
+       100,
+       200,
+       100,
+       0)
+{
+       this->client = client; 
+}
+
+FreezeFrameWindow::~FreezeFrameWindow()
+{
+}
+
+void FreezeFrameWindow::create_objects()
+{
+       int x = 10, y = 10;
+       add_tool(enabled = new FreezeFrameToggle(client, 
+               &client->config.enabled,
+               x, 
+               y,
+               _("Enabled")));
+// Try using extra effect for the line double since it doesn't
+// change the overhead.
+//     y += 30;
+//     add_tool(line_double = new FreezeFrameToggle(client, 
+//             &client->config.line_double,
+//             x, 
+//             y,
+//             _("Line double")));
+       show_window();
+       flush();
+}
+
+
+
+
+
+
+FreezeFrameToggle::FreezeFrameToggle(FreezeFrameMain *client, 
+       int *value, 
+       int x, 
+       int y,
+       char *text)
+ : BC_CheckBox(x, y, *value, text)
+{
+       this->client = client;
+       this->value = value;
+}
+FreezeFrameToggle::~FreezeFrameToggle()
+{
+}
+int FreezeFrameToggle::handle_event()
+{
+       *value = get_value();
+       client->send_configure_change();
+       return 1;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+FreezeFrameMain::FreezeFrameMain(PluginServer *server)
+ : PluginVClient(server)
+{
+       
+       first_frame = 0;
+       first_frame_position = -1;
+}
+
+FreezeFrameMain::~FreezeFrameMain()
+{
+       
+       if(first_frame) delete first_frame;
+}
+
+const char* FreezeFrameMain::plugin_title() { return _("Freeze Frame"); }
+int FreezeFrameMain::is_synthesis() { return 1; }
+int FreezeFrameMain::is_realtime() { return 1; }
+
+
+NEW_WINDOW_MACRO(FreezeFrameMain, FreezeFrameWindow)
+
+int FreezeFrameMain::load_configuration()
+{
+       KeyFrame *prev_keyframe = get_prev_keyframe(get_source_position());
+       int64_t prev_position = edl_to_local(prev_keyframe->position);
+       if(prev_position < get_source_start()) prev_position = get_source_start();
+       read_data(prev_keyframe);
+// Invalidate stored frame
+       if(config.enabled) first_frame_position = prev_position;
+       return 0;
+}
+
+void FreezeFrameMain::update_gui()
+{
+       if(thread)
+       {
+               load_configuration();
+               ((FreezeFrameWindow*)thread->window)->lock_window();
+               ((FreezeFrameWindow*)thread->window)->enabled->update(config.enabled);
+//             thread->window->line_double->update(config.line_double);
+               thread->window->unlock_window();
+       }
+}
+
+void FreezeFrameMain::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("FREEZEFRAME");
+       output.append_tag();
+       if(config.enabled)
+       {
+               output.tag.set_title("ENABLED");
+               output.append_tag();
+               output.tag.set_title("/ENABLED");
+               output.append_tag();
+       }
+       if(config.line_double)
+       {
+               output.tag.set_title("LINE_DOUBLE");
+               output.append_tag();
+               output.tag.set_title("/LINE_DOUBLE");
+               output.append_tag();
+       }
+       output.tag.set_title("/FREEZEFRAME");
+       output.append_tag();
+       output.append_newline();
+       output.terminate_string();
+// data is now in *text
+}
+
+void FreezeFrameMain::read_data(KeyFrame *keyframe)
+{
+       FileXML input;
+
+       input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
+
+       int result = 0;
+       config.enabled = 0;
+       config.line_double = 0;
+
+       while(!result)
+       {
+               result = input.read_tag();
+
+               if(!result)
+               {
+                       if(input.tag.title_is("ENABLED"))
+                       {
+                               config.enabled = 1;
+                       }
+                       if(input.tag.title_is("LINE_DOUBLE"))
+                       {
+                               config.line_double = 1;
+                       }
+               }
+       }
+}
+
+
+
+
+
+
+
+int FreezeFrameMain::process_buffer(VFrame *frame,
+               int64_t start_position,
+               double frame_rate)
+{
+       int64_t previous_first_frame = first_frame_position;
+       load_configuration();
+
+// Just entered frozen range
+       if(!first_frame && config.enabled)
+       {
+               if(!first_frame)
+                       first_frame = new VFrame(0, 
+                               -1,
+                               frame->get_w(), 
+                               frame->get_h(),
+                               frame->get_color_model(),
+                               -1);
+//printf("FreezeFrameMain::process_buffer 1 %jd\n", first_frame_position);
+               read_frame(first_frame, 
+                               0, 
+                               get_direction() == PLAY_REVERSE ? first_frame_position + 1 : first_frame_position,
+                               frame_rate,
+                               get_use_opengl());
+               if(get_use_opengl()) return run_opengl();
+               frame->copy_from(first_frame);
+       }
+       else
+// Still not frozen
+       if(!first_frame && !config.enabled)
+       {
+               read_frame(frame, 
+                       0, 
+                       start_position,
+                       frame_rate,
+                       get_use_opengl());
+       }
+       else
+// Just left frozen range
+       if(first_frame && !config.enabled)
+       {
+               delete first_frame;
+               first_frame = 0;
+               read_frame(frame, 
+                       0, 
+                       start_position,
+                       frame_rate,
+                       get_use_opengl());
+       }
+       else
+// Still frozen
+       if(first_frame && config.enabled)
+       {
+// Had a keyframe in frozen range.  Load new first frame
+               if(previous_first_frame != first_frame_position)
+               {
+                       read_frame(first_frame, 
+                               0, 
+                               get_direction() == PLAY_REVERSE ? first_frame_position + 1 : first_frame_position,
+                               frame_rate,
+                               get_use_opengl());
+               }
+               if(get_use_opengl()) return run_opengl();
+               frame->copy_from(first_frame);
+       }
+
+
+// Line double to support interlacing
+//     if(config.line_double && config.enabled)
+//     {
+//             for(int i = 0; i < frame->get_h() - 1; i += 2)
+//             {
+//                     memcpy(frame->get_rows()[i + 1], 
+//                             frame->get_rows()[i], 
+//                             frame->get_bytes_per_line());
+//             }
+//     }
+
+
+
+       return 0;
+}
+
+int FreezeFrameMain::handle_opengl()
+{
+#ifdef HAVE_GL
+       get_output()->enable_opengl();
+       get_output()->init_screen();
+       first_frame->to_texture();
+       first_frame->bind_texture(0);
+       first_frame->draw_texture();
+       get_output()->set_opengl_state(VFrame::SCREEN);
+#endif
+       return 0;
+}
+
+