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