Fourth set of 50 GPL attribution for CV-Contributors added +
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / loopvideo / loopvideo.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 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 "clip.h"
25 #include "bchash.h"
26 #include "filexml.h"
27 #include "guicast.h"
28 #include "language.h"
29 #include "pluginvclient.h"
30 #include "transportque.h"
31
32 #include <string.h>
33
34 class LoopVideo;
35
36 class LoopVideoConfig
37 {
38 public:
39         LoopVideoConfig();
40         int64_t frames;
41 };
42
43
44 class LoopVideoFrames : public BC_TextBox
45 {
46 public:
47         LoopVideoFrames(LoopVideo *plugin,
48                 int x,
49                 int y);
50         int handle_event();
51         LoopVideo *plugin;
52 };
53
54 class LoopVideoWindow : public PluginClientWindow
55 {
56 public:
57         LoopVideoWindow(LoopVideo *plugin);
58         ~LoopVideoWindow();
59         void create_objects();
60         LoopVideo *plugin;
61         LoopVideoFrames *frames;
62 };
63
64
65 class LoopVideo : public PluginVClient
66 {
67 public:
68         LoopVideo(PluginServer *server);
69         ~LoopVideo();
70
71         PLUGIN_CLASS_MEMBERS(LoopVideoConfig)
72
73         void save_data(KeyFrame *keyframe);
74         void read_data(KeyFrame *keyframe);
75         void update_gui();
76         int is_realtime();
77         int is_synthesis();
78         int process_buffer(VFrame *frame,
79                 int64_t start_position,
80                 double frame_rate);
81 };
82
83
84
85
86
87
88
89 REGISTER_PLUGIN(LoopVideo);
90
91
92
93 LoopVideoConfig::LoopVideoConfig()
94 {
95         frames = 30;
96 }
97
98
99
100
101
102 LoopVideoWindow::LoopVideoWindow(LoopVideo *plugin)
103  : PluginClientWindow(plugin,
104         xS(160),
105         yS(70),
106         xS(160),
107         yS(70),
108         0)
109 {
110         this->plugin = plugin;
111 }
112
113 LoopVideoWindow::~LoopVideoWindow()
114 {
115 }
116
117 void LoopVideoWindow::create_objects()
118 {
119         int xs10 = xS(10);
120         int ys10 = yS(10), ys20 = yS(20);
121         int x = xs10, y = ys10;
122
123         add_subwindow(new BC_Title(x, y, _("Frames to loop:")));
124         y += ys20;
125         add_subwindow(frames = new LoopVideoFrames(plugin,
126                 x,
127                 y));
128         show_window();
129         flush();
130 }
131
132
133
134
135
136
137
138
139
140
141
142 LoopVideoFrames::LoopVideoFrames(LoopVideo *plugin,
143         int x,
144         int y)
145  : BC_TextBox(x,
146         y,
147         xS(100),
148         1,
149         plugin->config.frames)
150 {
151         this->plugin = plugin;
152 }
153
154 int LoopVideoFrames::handle_event()
155 {
156         plugin->config.frames = atol(get_text());
157         plugin->config.frames = MAX(1, plugin->config.frames);
158         plugin->send_configure_change();
159         return 1;
160 }
161
162
163
164
165
166
167
168
169
170 LoopVideo::LoopVideo(PluginServer *server)
171  : PluginVClient(server)
172 {
173
174 }
175
176
177 LoopVideo::~LoopVideo()
178 {
179
180 }
181
182 const char* LoopVideo::plugin_title() { return N_("Loop video"); }
183 int LoopVideo::is_realtime() { return 1; }
184 int LoopVideo::is_synthesis() { return 1; }
185
186
187 NEW_WINDOW_MACRO(LoopVideo, LoopVideoWindow)
188
189
190
191 int LoopVideo::process_buffer(VFrame *frame,
192                 int64_t start_position,
193                 double frame_rate)
194 {
195         int64_t current_loop_position;
196
197 // Truncate to next keyframe
198         if(get_direction() == PLAY_FORWARD)
199         {
200 // Get start of current loop
201                 KeyFrame *prev_keyframe = get_prev_keyframe(start_position);
202                 int64_t prev_position = edl_to_local(prev_keyframe->position);
203                 if(prev_position == 0)
204                         prev_position = get_source_start();
205                 read_data(prev_keyframe);
206
207 // Get start of fragment in current loop
208                 current_loop_position = prev_position +
209                         ((start_position - prev_position) %
210                                 config.frames);
211                 while(current_loop_position < prev_position) current_loop_position += config.frames;
212                 while(current_loop_position >= prev_position + config.frames) current_loop_position -= config.frames;
213         }
214         else
215         {
216                 KeyFrame *prev_keyframe = get_next_keyframe(start_position);
217                 int64_t prev_position = edl_to_local(prev_keyframe->position);
218                 if(prev_position == 0)
219                         prev_position = get_source_start() + get_total_len();
220                 read_data(prev_keyframe);
221
222                 current_loop_position = prev_position -
223                         ((prev_position - start_position) %
224                                   config.frames);
225                 while(current_loop_position <= prev_position - config.frames) current_loop_position += config.frames;
226                 while(current_loop_position > prev_position) current_loop_position -= config.frames;
227         }
228
229
230 // printf("LoopVideo::process_buffer 100 %lld %lld %lld %d\n",
231 // current_position, current_loop_position, current_loop_end, fragment_size);
232         read_frame(frame,
233                 0,
234                 current_loop_position,
235                 frame_rate,
236                 0);
237
238         return 0;
239 }
240
241
242
243
244 int LoopVideo::load_configuration()
245 {
246         KeyFrame *prev_keyframe;
247         int64_t old_frames = config.frames;
248         prev_keyframe = get_prev_keyframe(get_source_position());
249         read_data(prev_keyframe);
250         config.frames = MAX(config.frames, 1);
251         return old_frames != config.frames;
252 }
253
254
255 void LoopVideo::save_data(KeyFrame *keyframe)
256 {
257         FileXML output;
258
259 // cause data to be stored directly in text
260         output.set_shared_output(keyframe->xbuf);
261         output.tag.set_title("LOOPVIDEO");
262         output.tag.set_property("FRAMES", config.frames);
263         output.append_tag();
264         output.tag.set_title("/LOOPVIDEO");
265         output.append_tag();
266         output.append_newline();
267         output.terminate_string();
268 }
269
270 void LoopVideo::read_data(KeyFrame *keyframe)
271 {
272         FileXML input;
273
274         input.set_shared_input(keyframe->xbuf);
275
276         while(!input.read_tag())
277         {
278                 if(input.tag.title_is("LOOPVIDEO"))
279                 {
280                         config.frames = input.tag.get_property("FRAMES", config.frames);
281                 }
282         }
283 }
284
285 void LoopVideo::update_gui()
286 {
287         if(thread)
288         {
289                 load_configuration();
290                 thread->window->lock_window();
291                 ((LoopVideoWindow*)thread->window)->frames->update(config.frames);
292                 thread->window->unlock_window();
293         }
294 }
295
296
297
298
299