67904ed698ab7c3f233258c98255aa125fbda7f5
[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(frame->get_w(), frame->get_h(),
262                                 frame->get_color_model(), 0);
263 //printf("FreezeFrameMain::process_buffer 1 %jd\n", first_frame_position);
264                 read_frame(first_frame,
265                                 0,
266                                 get_direction() == PLAY_REVERSE ? first_frame_position + 1 : first_frame_position,
267                                 frame_rate,
268                                 get_use_opengl());
269                 if(get_use_opengl()) return run_opengl();
270                 frame->copy_from(first_frame);
271         }
272         else
273 // Still not frozen
274         if(!first_frame && !config.enabled)
275         {
276                 read_frame(frame,
277                         0,
278                         start_position,
279                         frame_rate,
280                         get_use_opengl());
281         }
282         else
283 // Just left frozen range
284         if(first_frame && !config.enabled)
285         {
286                 delete first_frame;
287                 first_frame = 0;
288                 read_frame(frame,
289                         0,
290                         start_position,
291                         frame_rate,
292                         get_use_opengl());
293         }
294         else
295 // Still frozen
296         if(first_frame && config.enabled)
297         {
298 // Had a keyframe in frozen range.  Load new first frame
299                 if(previous_first_frame != first_frame_position)
300                 {
301                         read_frame(first_frame,
302                                 0,
303                                 get_direction() == PLAY_REVERSE ? first_frame_position + 1 : first_frame_position,
304                                 frame_rate,
305                                 get_use_opengl());
306                 }
307                 if(get_use_opengl()) return run_opengl();
308                 frame->copy_from(first_frame);
309         }
310
311
312 // Line double to support interlacing
313 //      if(config.line_double && config.enabled)
314 //      {
315 //              for(int i = 0; i < frame->get_h() - 1; i += 2)
316 //              {
317 //                      memcpy(frame->get_rows()[i + 1],
318 //                              frame->get_rows()[i],
319 //                              frame->get_bytes_per_line());
320 //              }
321 //      }
322
323
324
325         return 0;
326 }
327
328 int FreezeFrameMain::handle_opengl()
329 {
330 #ifdef HAVE_GL
331         get_output()->enable_opengl();
332         get_output()->init_screen();
333         first_frame->to_texture();
334         first_frame->bind_texture(0);
335         first_frame->draw_texture();
336         get_output()->set_opengl_state(VFrame::SCREEN);
337 #endif
338         return 0;
339 }
340
341