Credit Andrew - fix vorbis audio which was scratchy and ensure aging plugin does...
[goodguy/cinelerra.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  * Copyright (C) 2003-2016 Cinelerra CV contributors
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22
23 #include "bcdisplayinfo.h"
24 #include "bchash.h"
25 #include "filexml.h"
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, xS(160), yS(40), xS(160), yS(40), 0)
80 {
81         this->client = client;
82 }
83
84 FreezeFrameWindow::~FreezeFrameWindow()
85 {
86 }
87
88 void FreezeFrameWindow::create_objects()
89 {
90         int x = xS(10), y = yS(10);
91         add_tool(enabled = new FreezeFrameToggle(client,
92                 &client->config.enabled,
93                 x,
94                 y,
95                 _("Enabled")));
96 // Try using extra effect for the line double since it doesn't
97 // change the overhead.
98 //      y += yS(30);
99 //      add_tool(line_double = new FreezeFrameToggle(client,
100 //              &client->config.line_double,
101 //              x,
102 //              y,
103 //              _("Line double")));
104         show_window();
105         flush();
106 }
107
108
109
110
111
112
113 FreezeFrameToggle::FreezeFrameToggle(FreezeFrameMain *client,
114         int *value,
115         int x,
116         int y,
117         char *text)
118  : BC_CheckBox(x, y, *value, text)
119 {
120         this->client = client;
121         this->value = value;
122 }
123 FreezeFrameToggle::~FreezeFrameToggle()
124 {
125 }
126 int FreezeFrameToggle::handle_event()
127 {
128         *value = get_value();
129         client->send_configure_change();
130         return 1;
131 }
132
133
134
135
136
137
138
139
140
141
142
143
144 FreezeFrameMain::FreezeFrameMain(PluginServer *server)
145  : PluginVClient(server)
146 {
147
148         first_frame = 0;
149         first_frame_position = -1;
150 }
151
152 FreezeFrameMain::~FreezeFrameMain()
153 {
154
155         if(first_frame) delete first_frame;
156 }
157
158 const char* FreezeFrameMain::plugin_title() { return N_("Freeze Frame"); }
159 int FreezeFrameMain::is_synthesis() { return 1; }
160 int FreezeFrameMain::is_realtime() { return 1; }
161
162
163 NEW_WINDOW_MACRO(FreezeFrameMain, FreezeFrameWindow)
164
165 int FreezeFrameMain::load_configuration()
166 {
167         KeyFrame *prev_keyframe = get_prev_keyframe(get_source_position());
168         int64_t prev_position = edl_to_local(prev_keyframe->position);
169         if(prev_position < get_source_start()) prev_position = get_source_start();
170         read_data(prev_keyframe);
171 // Invalidate stored frame
172         if(config.enabled) first_frame_position = prev_position;
173         return 0;
174 }
175
176 void FreezeFrameMain::update_gui()
177 {
178         if(thread)
179         {
180                 load_configuration();
181                 ((FreezeFrameWindow*)thread->window)->lock_window();
182                 ((FreezeFrameWindow*)thread->window)->enabled->update(config.enabled);
183 //              thread->window->line_double->update(config.line_double);
184                 thread->window->unlock_window();
185         }
186 }
187
188 void FreezeFrameMain::save_data(KeyFrame *keyframe)
189 {
190         FileXML output;
191
192 // cause data to be stored directly in text
193         output.set_shared_output(keyframe->xbuf);
194         output.tag.set_title("FREEZEFRAME");
195         output.append_tag();
196         if(config.enabled)
197         {
198                 output.tag.set_title("ENABLED");
199                 output.append_tag();
200                 output.tag.set_title("/ENABLED");
201                 output.append_tag();
202         }
203         if(config.line_double)
204         {
205                 output.tag.set_title("LINE_DOUBLE");
206                 output.append_tag();
207                 output.tag.set_title("/LINE_DOUBLE");
208                 output.append_tag();
209         }
210         output.tag.set_title("/FREEZEFRAME");
211         output.append_tag();
212         output.append_newline();
213         output.terminate_string();
214 // data is now in *text
215 }
216
217 void FreezeFrameMain::read_data(KeyFrame *keyframe)
218 {
219         FileXML input;
220
221         input.set_shared_input(keyframe->xbuf);
222
223         int result = 0;
224         config.enabled = 0;
225         config.line_double = 0;
226
227         while(!result)
228         {
229                 result = input.read_tag();
230
231                 if(!result)
232                 {
233                         if(input.tag.title_is("ENABLED"))
234                         {
235                                 config.enabled = 1;
236                         }
237                         if(input.tag.title_is("LINE_DOUBLE"))
238                         {
239                                 config.line_double = 1;
240                         }
241                 }
242         }
243 }
244
245
246
247
248
249
250
251 int FreezeFrameMain::process_buffer(VFrame *frame,
252                 int64_t start_position,
253                 double frame_rate)
254 {
255         int64_t previous_first_frame = first_frame_position;
256         load_configuration();
257
258 // Just entered frozen range
259         if(!first_frame && config.enabled)
260         {
261                 if(!first_frame)
262                         first_frame = new VFrame(frame->get_w(), frame->get_h(),
263                                 frame->get_color_model(), 0);
264 //printf("FreezeFrameMain::process_buffer 1 %jd\n", first_frame_position);
265                 read_frame(first_frame,
266                                 0,
267                                 get_direction() == PLAY_REVERSE ? first_frame_position + 1 : first_frame_position,
268                                 frame_rate,
269                                 get_use_opengl());
270                 if(get_use_opengl()) return run_opengl();
271                 frame->copy_from(first_frame);
272         }
273         else
274 // Still not frozen
275         if(!first_frame && !config.enabled)
276         {
277                 read_frame(frame,
278                         0,
279                         start_position,
280                         frame_rate,
281                         get_use_opengl());
282         }
283         else
284 // Just left frozen range
285         if(first_frame && !config.enabled)
286         {
287                 delete first_frame;
288                 first_frame = 0;
289                 read_frame(frame,
290                         0,
291                         start_position,
292                         frame_rate,
293                         get_use_opengl());
294         }
295         else
296 // Still frozen
297         if(first_frame && config.enabled)
298         {
299 // Had a keyframe in frozen range.  Load new first frame
300                 if(previous_first_frame != first_frame_position)
301                 {
302                         read_frame(first_frame,
303                                 0,
304                                 get_direction() == PLAY_REVERSE ? first_frame_position + 1 : first_frame_position,
305                                 frame_rate,
306                                 get_use_opengl());
307                 }
308                 if(get_use_opengl()) return run_opengl();
309                 frame->copy_from(first_frame);
310         }
311
312
313 // Line double to support interlacing
314 //      if(config.line_double && config.enabled)
315 //      {
316 //              for(int i = 0; i < frame->get_h() - 1; i += 2)
317 //              {
318 //                      memcpy(frame->get_rows()[i + 1],
319 //                              frame->get_rows()[i],
320 //                              frame->get_bytes_per_line());
321 //              }
322 //      }
323
324
325
326         return 0;
327 }
328
329 int FreezeFrameMain::handle_opengl()
330 {
331 #ifdef HAVE_GL
332         get_output()->enable_opengl();
333         get_output()->init_screen();
334         first_frame->to_texture();
335         first_frame->bind_texture(0);
336         first_frame->draw_texture();
337         get_output()->set_opengl_state(VFrame::SCREEN);
338 #endif
339         return 0;
340 }
341
342