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