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