replace plugin icon data with CV ver for merge, replace manual.pdf
[goodguy/history.git] / cinelerra-5.0 / plugins / freezeframe / freezeframe.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
5  * 
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.
10  * 
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.
15  * 
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
19  * 
20  */
21
22 #include "bcdisplayinfo.h"
23 #include "bchash.h"
24 #include "filexml.h"
25 #include "format.inc"
26 #include "freezeframe.h"
27 #include "language.h"
28 #include "transportque.inc"
29
30
31
32 #include <string.h>
33
34
35 REGISTER_PLUGIN(FreezeFrameMain)
36
37
38
39
40
41 FreezeFrameConfig::FreezeFrameConfig()
42 {
43         enabled = 0;
44         line_double = 0;
45 }
46
47 void FreezeFrameConfig::copy_from(FreezeFrameConfig &that)
48 {
49         enabled = that.enabled;
50         line_double = that.line_double;
51 }
52
53 int FreezeFrameConfig::equivalent(FreezeFrameConfig &that)
54 {
55         return enabled == that.enabled &&
56                 line_double == that.line_double;
57 }
58
59 void FreezeFrameConfig::interpolate(FreezeFrameConfig &prev, 
60         FreezeFrameConfig &next, 
61         long prev_frame, 
62         long next_frame, 
63         long current_frame)
64 {
65         this->enabled = prev.enabled;
66         this->line_double = prev.line_double;
67 }
68
69
70
71
72
73
74
75
76
77
78 FreezeFrameWindow::FreezeFrameWindow(FreezeFrameMain *client)
79  : PluginClientWindow(client,
80         200,
81         100,
82         200,
83         100,
84         0)
85 {
86         this->client = client; 
87 }
88
89 FreezeFrameWindow::~FreezeFrameWindow()
90 {
91 }
92
93 void FreezeFrameWindow::create_objects()
94 {
95         int x = 10, y = 10;
96         add_tool(enabled = new FreezeFrameToggle(client, 
97                 &client->config.enabled,
98                 x, 
99                 y,
100                 _("Enabled")));
101 // Try using extra effect for the line double since it doesn't
102 // change the overhead.
103 //      y += 30;
104 //      add_tool(line_double = new FreezeFrameToggle(client, 
105 //              &client->config.line_double,
106 //              x, 
107 //              y,
108 //              _("Line double")));
109         show_window();
110         flush();
111 }
112
113
114
115
116
117
118 FreezeFrameToggle::FreezeFrameToggle(FreezeFrameMain *client, 
119         int *value, 
120         int x, 
121         int y,
122         char *text)
123  : BC_CheckBox(x, y, *value, text)
124 {
125         this->client = client;
126         this->value = value;
127 }
128 FreezeFrameToggle::~FreezeFrameToggle()
129 {
130 }
131 int FreezeFrameToggle::handle_event()
132 {
133         *value = get_value();
134         client->send_configure_change();
135         return 1;
136 }
137
138
139
140
141
142
143
144
145
146
147
148
149 FreezeFrameMain::FreezeFrameMain(PluginServer *server)
150  : PluginVClient(server)
151 {
152         
153         first_frame = 0;
154         first_frame_position = -1;
155 }
156
157 FreezeFrameMain::~FreezeFrameMain()
158 {
159         
160         if(first_frame) delete first_frame;
161 }
162
163 const char* FreezeFrameMain::plugin_title() { return _("Freeze Frame"); }
164 int FreezeFrameMain::is_synthesis() { return 1; }
165 int FreezeFrameMain::is_realtime() { return 1; }
166
167
168 NEW_WINDOW_MACRO(FreezeFrameMain, FreezeFrameWindow)
169
170 int FreezeFrameMain::load_configuration()
171 {
172         KeyFrame *prev_keyframe = get_prev_keyframe(get_source_position());
173         int64_t prev_position = edl_to_local(prev_keyframe->position);
174         if(prev_position < get_source_start()) prev_position = get_source_start();
175         read_data(prev_keyframe);
176 // Invalidate stored frame
177         if(config.enabled) first_frame_position = prev_position;
178         return 0;
179 }
180
181 void FreezeFrameMain::update_gui()
182 {
183         if(thread)
184         {
185                 load_configuration();
186                 ((FreezeFrameWindow*)thread->window)->lock_window();
187                 ((FreezeFrameWindow*)thread->window)->enabled->update(config.enabled);
188 //              thread->window->line_double->update(config.line_double);
189                 thread->window->unlock_window();
190         }
191 }
192
193 void FreezeFrameMain::save_data(KeyFrame *keyframe)
194 {
195         FileXML output;
196
197 // cause data to be stored directly in text
198         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
199         output.tag.set_title("FREEZEFRAME");
200         output.append_tag();
201         if(config.enabled)
202         {
203                 output.tag.set_title("ENABLED");
204                 output.append_tag();
205         }
206         if(config.line_double)
207         {
208                 output.tag.set_title("LINE_DOUBLE");
209                 output.append_tag();
210         }
211         output.terminate_string();
212 // data is now in *text
213 }
214
215 void FreezeFrameMain::read_data(KeyFrame *keyframe)
216 {
217         FileXML input;
218
219         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
220
221         int result = 0;
222         config.enabled = 0;
223         config.line_double = 0;
224
225         while(!result)
226         {
227                 result = input.read_tag();
228
229                 if(!result)
230                 {
231                         if(input.tag.title_is("ENABLED"))
232                         {
233                                 config.enabled = 1;
234                         }
235                         if(input.tag.title_is("LINE_DOUBLE"))
236                         {
237                                 config.line_double = 1;
238                         }
239                 }
240         }
241 }
242
243
244
245
246
247
248
249 int FreezeFrameMain::process_buffer(VFrame *frame,
250                 int64_t start_position,
251                 double frame_rate)
252 {
253         int64_t previous_first_frame = first_frame_position;
254         load_configuration();
255
256 // Just entered frozen range
257         if(!first_frame && config.enabled)
258         {
259                 if(!first_frame)
260                         first_frame = new VFrame(0, 
261                                 -1,
262                                 frame->get_w(), 
263                                 frame->get_h(),
264                                 frame->get_color_model(),
265                                 -1);
266 //printf("FreezeFrameMain::process_buffer 1 " _LD "\n", first_frame_position);
267                 read_frame(first_frame, 
268                                 0, 
269                                 get_direction() == PLAY_REVERSE ? first_frame_position + 1 : first_frame_position,
270                                 frame_rate,
271                                 get_use_opengl());
272                 if(get_use_opengl()) return run_opengl();
273                 frame->copy_from(first_frame);
274         }
275         else
276 // Still not frozen
277         if(!first_frame && !config.enabled)
278         {
279                 read_frame(frame, 
280                         0, 
281                         start_position,
282                         frame_rate,
283                         get_use_opengl());
284         }
285         else
286 // Just left frozen range
287         if(first_frame && !config.enabled)
288         {
289                 delete first_frame;
290                 first_frame = 0;
291                 read_frame(frame, 
292                         0, 
293                         start_position,
294                         frame_rate,
295                         get_use_opengl());
296         }
297         else
298 // Still frozen
299         if(first_frame && config.enabled)
300         {
301 // Had a keyframe in frozen range.  Load new first frame
302                 if(previous_first_frame != first_frame_position)
303                 {
304                         read_frame(first_frame, 
305                                 0, 
306                                 get_direction() == PLAY_REVERSE ? first_frame_position + 1 : first_frame_position,
307                                 frame_rate,
308                                 get_use_opengl());
309                 }
310                 if(get_use_opengl()) return run_opengl();
311                 frame->copy_from(first_frame);
312         }
313
314
315 // Line double to support interlacing
316 //      if(config.line_double && config.enabled)
317 //      {
318 //              for(int i = 0; i < frame->get_h() - 1; i += 2)
319 //              {
320 //                      memcpy(frame->get_rows()[i + 1], 
321 //                              frame->get_rows()[i], 
322 //                              frame->get_bytes_per_line());
323 //              }
324 //      }
325
326
327
328         return 0;
329 }
330
331 int FreezeFrameMain::handle_opengl()
332 {
333 #ifdef HAVE_GL
334         get_output()->enable_opengl();
335         get_output()->init_screen();
336         first_frame->to_texture();
337         first_frame->bind_texture(0);
338         first_frame->draw_texture();
339         get_output()->set_opengl_state(VFrame::SCREEN);
340 #endif
341         return 0;
342 }
343
344