08d7d08c6a77a06f6c73e9c3b21c8c7ce01ab946
[goodguy/history.git] / 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                 output.tag.set_title("/ENABLED");
206                 output.append_tag();
207         }
208         if(config.line_double)
209         {
210                 output.tag.set_title("LINE_DOUBLE");
211                 output.append_tag();
212                 output.tag.set_title("/LINE_DOUBLE");
213                 output.append_tag();
214         }
215         output.tag.set_title("/FREEZEFRAME");
216         output.append_tag();
217         output.append_newline();
218         output.terminate_string();
219 // data is now in *text
220 }
221
222 void FreezeFrameMain::read_data(KeyFrame *keyframe)
223 {
224         FileXML input;
225
226         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
227
228         int result = 0;
229         config.enabled = 0;
230         config.line_double = 0;
231
232         while(!result)
233         {
234                 result = input.read_tag();
235
236                 if(!result)
237                 {
238                         if(input.tag.title_is("ENABLED"))
239                         {
240                                 config.enabled = 1;
241                         }
242                         if(input.tag.title_is("LINE_DOUBLE"))
243                         {
244                                 config.line_double = 1;
245                         }
246                 }
247         }
248 }
249
250
251
252
253
254
255
256 int FreezeFrameMain::process_buffer(VFrame *frame,
257                 int64_t start_position,
258                 double frame_rate)
259 {
260         int64_t previous_first_frame = first_frame_position;
261         load_configuration();
262
263 // Just entered frozen range
264         if(!first_frame && config.enabled)
265         {
266                 if(!first_frame)
267                         first_frame = new VFrame(0, 
268                                 -1,
269                                 frame->get_w(), 
270                                 frame->get_h(),
271                                 frame->get_color_model(),
272                                 -1);
273 //printf("FreezeFrameMain::process_buffer 1 %jd\n", first_frame_position);
274                 read_frame(first_frame, 
275                                 0, 
276                                 get_direction() == PLAY_REVERSE ? first_frame_position + 1 : first_frame_position,
277                                 frame_rate,
278                                 get_use_opengl());
279                 if(get_use_opengl()) return run_opengl();
280                 frame->copy_from(first_frame);
281         }
282         else
283 // Still not frozen
284         if(!first_frame && !config.enabled)
285         {
286                 read_frame(frame, 
287                         0, 
288                         start_position,
289                         frame_rate,
290                         get_use_opengl());
291         }
292         else
293 // Just left frozen range
294         if(first_frame && !config.enabled)
295         {
296                 delete first_frame;
297                 first_frame = 0;
298                 read_frame(frame, 
299                         0, 
300                         start_position,
301                         frame_rate,
302                         get_use_opengl());
303         }
304         else
305 // Still frozen
306         if(first_frame && config.enabled)
307         {
308 // Had a keyframe in frozen range.  Load new first frame
309                 if(previous_first_frame != first_frame_position)
310                 {
311                         read_frame(first_frame, 
312                                 0, 
313                                 get_direction() == PLAY_REVERSE ? first_frame_position + 1 : first_frame_position,
314                                 frame_rate,
315                                 get_use_opengl());
316                 }
317                 if(get_use_opengl()) return run_opengl();
318                 frame->copy_from(first_frame);
319         }
320
321
322 // Line double to support interlacing
323 //      if(config.line_double && config.enabled)
324 //      {
325 //              for(int i = 0; i < frame->get_h() - 1; i += 2)
326 //              {
327 //                      memcpy(frame->get_rows()[i + 1], 
328 //                              frame->get_rows()[i], 
329 //                              frame->get_bytes_per_line());
330 //              }
331 //      }
332
333
334
335         return 0;
336 }
337
338 int FreezeFrameMain::handle_opengl()
339 {
340 #ifdef HAVE_GL
341         get_output()->enable_opengl();
342         get_output()->init_screen();
343         first_frame->to_texture();
344         first_frame->bind_texture(0);
345         first_frame->draw_texture();
346         get_output()->set_opengl_state(VFrame::SCREEN);
347 #endif
348         return 0;
349 }
350
351